为什么这个代码在setTimeout中调用但不在其外部时有效?

时间:2013-01-18 01:13:08

标签: javascript settimeout

我有一个eventHandler,每当一个节点插入一个contenteditable div时就会被触发。此eventHandler将新插入的div node替换为p node

问题是在更换后放置光标。基本上光标没有正确放置,也就是说,光标在预期放置在新创建的p节点中时消失。奇怪的是,内容可编辑div仍然具有焦点并且转储window.selection对象显示正确设置的范围。

解决此问题的唯一方法是使用setTimeout进行脏修复。


问。为什么在使用setTimeout调用placeCursor()时却有效呢?


相关守则:

JSFiddle

obj.addEventListener("DOMNodeInserted", onNodeInsert, false);

function onNodeInsert(e) {
    var range    = document.createRange(),
        sel      = window.getSelection(),
        newNode  = e.target,
        tagName  = newNode.tagName.toLowerCase(),
        lnbrNode = document.createElement('br'),
        pNode    = document.createElement('p');

    if (tagName === 'div' && newNode.getAttribute("id") === null) {
        // First we remove the event listener so that it doesn't get triggered again
        this.removeEventListener('DOMNodeInserted', onNodeInsert, false);

        // Creates a p node and removes the div
        newNode.parentNode.replaceChild(pNode, newNode);
        pNode.appendChild(lnbrNode);

        // Places the caret where it belongs
        var placeCursor = function () {
            range.setStart(pNode, 0);
            sel.removeAllRanges();
            sel.addRange(range);    
        }

        //placeCursor(); // DOES NOT WORK (cursor disappears)
        setTimeout(placeCursor,1); // WORKS

        //We can restore the event listener now
        this.addEventListener("DOMNodeInserted", onNodeInsert, false);
    }
}

有关更多背景信息,请参阅this post

1 个答案:

答案 0 :(得分:2)

我不知道如何做好解释,但是因为DOM持久性延迟。移动设备有很多问题。所以当执行监听器回调时,dom还没有准备好。

所以它不会起作用,因为你正在尝试管理一个选择。如果你设置超时,那么该函数将在4ms后执行,所以DOM有足够的时间来保持你的变化范围并进行你想要做的改变。

确实浏览器不需要推迟执行函数的工作,理论上你的代码在没有setTimeout的情况下是正确的,但是在处理由触发的侦听器时你可以通过多种方式找到这个“bug” DOM改变。

只是你知道。在我的桌面浏览器中,它的工作方式应该如此,但是,当我在上网本中运行它时,我需要使用setTimout来工作。