范围对象,获取选择父节点Chrome与Firefox

时间:2013-04-07 20:40:27

标签: javascript google-chrome firefox range

我正在尝试制作一个小型文本编辑器。

当我选择文字时,我想知道所选文字在spandiv中是否单独,然后我想更改此元素的样式。

示例:

<span style="font-size:12px">Hola</span>

如果我选择 Hola ,我想检索父节点<span style="font-size:12px">Hola</span>

<span style="font-size:56px">
Hola <span style="font-size:12px">Hello</span>
</span>

如果我选择 Hello ,我只想检索<span style="font-size:12px">Hello</span>

现在,当我在Chrome中尝试时,我会用

获得正确的结果
range.startContainer.parentNode;

但是在第二个例子中我使用Firefox检索

<span style="font-size:56px">
    Hola <span style="font-size:12px">Hello</span>
</span>

如何在Chrome和Firefox中获得相同的结果?

1 个答案:

答案 0 :(得分:8)

您的问题是,当一个或两个选择边界与DOM节点边界重合时,浏览器之间的选择会略有不同。例如,如果用户使用以下HTML在页面内容中选择了“bar”一词

<p>foo<i>bar</i></p>

...选择开始有四种不同的可能位置,所有这些位置在视觉上与用户完全相同:

  1. 在“foo”文本节点的末尾(节点“foo”,偏移3)
  2. <p>元素的一个子节点(节点<p>,偏移量1)之后
  3. <i>元素的零个孩子(节点<i>,偏移0)
  4. 之后
  5. 在“bar”文本节点的字符索引0处(节点“bar”,偏移0)
  6. 大多数浏览器在实践中不允许所有这些位置,但不幸的是,不同的浏览器做出了不同的选择。在Firefox中,您所做的选择会选择整个<span>元素,而选择范围的startContainer<span>的父节点。您可以通过检查范围来检测它是否选择单个节点:

    function rangeSelectsSingleNode(range) {
        var startNode = range.startContainer;
        return startNode === range.endContainer &&
               startNode.hasChildNodes() &&
               range.endOffset === range.startOffset + 1;
    }
    

    您可以使用它来检测您拥有的选择类型并相应地获取所选元素:

    var selectedElement = null;
    if (rangeSelectsSingleNode(range)) {
        // Selection encompasses a single element
        selectedElement = range.startContainer.childNodes[range.startOffset];
    } else if (range.startContainer.nodeType === 3) {
        // Selection range starts inside a text node, so get its parent
        selectedElement = range.startContainer.parentNode;
    } else {
        // Selection starts inside an element
        selectedElement = range.startContainer;
    }