我有一些与选择混乱的JavaScript。完整的代码做了一些我现在不愿讨论的复杂的事情,但是我有一个较小的测试用例,我在这里不明白。如果加载此页面,您应该看到一些文本和两个按钮。


双击“一些”将其选中,然后单击“选择”。 “ Some”在其周围延伸并且变成灰色。
然后再次双击“ Some”,然后单击“ Unselect”。跨度消失了,然后看页面内容就好像回到了开始的样子。
上次双击“某些”,单击“选择”,未选择任何内容。


最后一步失败了,因为选择的开始和结束被报告为位于页面上的不同节点中,即使它确定看起来像是同一节点,并且被报告为位于两个节点的位置0。我不明白为什么它的行为方式与第1步不同,因为在我看来,第2步就像第1步之前一样制作了该页面。此后,事情变得更奇怪了。 IE9中有类似但不完全相同的怪异行为。在Chrome中可以。

有人知道发生了什么吗?为什么在第3步中有两个不同的文本节点?当选择似乎从0扩展到5时(如在步骤1中一样),为什么两个选择的偏移量都为0?

这段代码还有其他一些错误,例如(尝试进行多项选择失败,许多其他事情不起作用),但我只是想以此情况作为起点:



<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
</head>
<div id="text">Some test words</div>
<button onclick='select()'>Select</button>
<button onclick='unselect()'>Unselect</button>
<div id="log"></div>
<script type='text/javascript'>
function log(message)
{
    var log = document.getElementById("log");
    log.innerHTML += message + "<br>";
}
function logSelection(selection)
{
    var range = selection.getRangeAt(0);
    var startContainer = range.startContainer;
    var endContainer = range.endContainer;
    log("Node types: " + startContainer.nodeType + ", " + endContainer.nodeType + ", " + range.commonAncestorContainer.nodeType)
    log("startContainer: " + (startContainer.nodeType == 3 ? startContainer.wholeText : startContainer.innerHTML));
    log("endContainer: " + (endContainer.nodeType == 3 ? endContainer.wholeText : endContainer.innerHTML));
    log("commonAncestorContainer: " + (range.commonAncestorContainer.nodeType == 3 ? range.commonAncestorContainer.wholeText : escape(range.commonAncestorContainer.innerHTML)));
    log("equal: " + (startContainer == endContainer));
    log("start: " + range.startOffset + " end: " + range.endOffset);
}
function select()
{
    var selection = window.getSelection();
    var range = selection.getRangeAt(0);
    var start = range.startOffset;
    var end = range.endOffset;
    var startContainer = range.startContainer;
    var endContainer = range.endContainer;
    logSelection(selection);
    startContainer.parentNode.innerHTML = startContainer.wholeText.substring(0, start)
        + "<span style='background-color: gray'>"
        + startContainer.wholeText.substring(start, end)
        + "</span>"
        + startContainer.wholeText.substring(end, startContainer.wholeText.length);
    selection.removeAllRanges();
    log("");
}
function unselect()
{
    var selection = window.getSelection();
    logSelection(selection);
    selection.removeAllRanges();
    var textDiv = $("#text");
    log("start: " + escape(textDiv.html()));
    textDiv.find("span").each(function () {
        var $span = $(this)
        $span.replaceWith($span.html());
    });
    log("final: " + escape(textDiv.html()));
    log("");
}
</script>

最佳答案

Chrome调试器可以清楚地显示您的假设出了哪些问题:

在采取任何措施之前,这是DOM:



选择之后,这是您的脚本如何更改它:



最后,在“取消选择”之后:



最后的显示揭示了问题:您没有创建字符串值节点,而是创建了一个新的字符串节点。父<div>包含两个文本节点,因此您的选择将跨越它们。

要明确的是,这里的脚本是问题所在:

textDiv.find("span").each(function () {
    var $span = $(this)
    $span.replaceWith($span.html());
});


spanspan字符串替换html()就是在创建新的文本节点。

关于javascript - Firefox和IE中的选择对象出现问题,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/30533871/

10-12 12:24
查看更多