简体   繁体   English

Javascript:Unitentional Focus Blur

[英]Javascript: Unitentional Focus Blur

In my endeavor to learn Javascript, I've been trying to implement a WYSIWYG code editor. 在我努力学习Javascript的过程中,我一直在尝试实现WYSIWYG代码编辑器。 Instead of implementing a content-editable div or a textarea , I took a leaf (rather, a lot of leaves) out of Ajax.org's ACE's book. 我没有实现内容可编辑的divtextarea ,而是从Ajax.org的ACE书中拿出一片叶子(而不是很多叶子)。

I have a listener div with tabIndex set to 0, to handle all input events. 我有一个侦听器divtabIndex设置为0,以处理所有输入事件。 All the components of the editor, like the text area, cursor and gutter, are children to this listener. 编辑器的所有组件(如文本区域,光标和装订线)都是此侦听器的子组件。 Since implementing mouse event handlers, I have been having a problem of the focus being lost on mousedown events. 自从实现鼠标事件处理程序以来,我一直遇到焦点在mousedown事件上丢失的问题。 Apparently, the blur event is being fired even when the mousedown event occurs in the listener. 显然,即使在侦听器中发生mousedown事件,也会触发blur事件。

After commenting out certain method calls and trying to see exactly what was causing the problem, I noticed that the culprit was the render method. 在评论出某些方法调用并试图确切地看到导致问题的原因之后,我注意到罪魁祸首是render方法。 Now, I call this method after every input, so it is very strange for the focus to be lost particularly when I call it for the mousedown event. 现在,我在每次输入后调用此方法,因此焦点丢失是非常奇怪的,特别是当我为mousedown事件调用它时。 On commenting out the render method, blur event is not fired when there is a mousedown event. 在注释掉render方法时,如果存在mousedown事件,则不会触发blur事件。

Going in further, it turns out that on commenting out the part where I replace the innerHTML of my text container, the problem disappears. 进一步说,事实证明,在注释掉我替换文本容器的innerHTML的部分时,问题就消失了。 This, again, is very odd since I use the replaceInnerHTML function at various places in the render function, but the problem seems to arise only from particularly updating the text div . 这又是很奇怪,因为我用的是replaceInnerHTML功能在各个地方render的功能,但这个问题似乎只有从特别更新的文字出现div

This is the replaceInnerHTML method (which I discovered here ): 这是replaceInnerHTML方法(我在这里发现):

function replaceInnerHTML(el, html) {
    var newEl = el.cloneNode(false);

    newEl.innerHTML = html;

    el.parentNode.replaceChild(newEl, el);

    return newEl;
}

And this is the update function for the text layer, on omitting which this problem does not occur: 这是文本层的更新功能,省略了不会发生此问题:

TextLayer.prototype.update = function(config) {
    html = [];

    var top = config.topRow;
    var last = config.lastRow;

    for(var i=top; i<=last; i++) {
        var line = this._session.getLine(i);
        if(line) {
            html.push('<div class="line" style="height:'+this.$characterSize.height+'px;">');
            this.renderLine(html, line);
            html.push('</div>');
        }       
    }   

    this._text = replaceInnerHTML(this._text, html.join(''));
    this.setSize(config.totalWidth, config.scrollHeight);
};

Why would the focus get blurred only due to replacing the innerHTML of a particular node, and that too only when it is called in case of a mousedown event? 为什么焦点只会因替换特定节点的innerHTML而变得模糊,而且只有在mousedown事件的情况下被调用时才会变焦?

Or am I going in a completely wrong direction in trying to debug this, and this problem is due to something else? 或者我在试图调试这个问题时走向了一个完全错误的方向,这个问题是由于其他原因造成的?

EDIT: 编辑:

Thanks to pimvdb, here is a fiddle reproducing the problem. 感谢pimvdb,这里有一个复制问题的小提琴。 http://jsfiddle.net/wG4Yy/39/ http://jsfiddle.net/wG4Yy/39/

The blur event seems to fire due to restructuring the nodes on the mousedown event. 由于重组了mousedown事件上的节点, blur事件似乎会触发。 I do not know how to solve problem. 我不知道如何解决问题。 I have tried using a document fragment instead of innerHTML, and I have also tried scheduling the update with setTimeout , but neither attempt worked. 我已经尝试使用文档片段而不是innerHTML,我也尝试使用setTimeout安排更新,但两种尝试均无效。

What should I do to resolve the issue? 我该怎么做才能解决这个问题?

When you want an element to get focus, it seems like the you have to click on an element that stays there. 当你想要一个元素获得焦点时,你似乎必须点击一个留在那里的元素。 If you replace it with another element, the browser is apparently not tricked into focusing that element. 如果你用另一个元素替换它,浏览器显然不会被欺骗聚焦那个元素。

What you can do is letting the browser finish its mousedown/focus etc. process, and focus the element manually afterwards. 您可以做的是让浏览器完成其mousedown / focus等过程,然后手动关注元素。 This can be accomplished with a setTimeout(..., 0) call: http://jsfiddle.net/wG4Yy/41/ . 这可以通过setTimeout(..., 0)调用来完成: http//jsfiddle.net/wG4Yy/41/

setTimeout(function() {
    wrapper.focus();
}, 0);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM