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

Range object , get Selection parent node Chrome vs Firefox

本文关键字:Chrome vs Firefox 父节点 选择 对象 获取 范围      更新时间:2023-09-26

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

当我选择一个文本时,我想知道所选文本是否单独存在于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中获得相同的结果?

您的问题是,当一个或两个选择边界与DOM节点边界重合时,浏览器之间的选择工作略有不同。例如,如果用户使用以下HTML

在页面内容中选择单词"bar"
<p>foo<i>bar</i></p>

…对于用户来说,选择开始有四个不同的位置,它们在视觉上看起来都是一样的:

  1. 在"foo"文本节点的末尾(节点"foo",偏移量3)
  2. <p>元素的一个子节点之后(节点<p>,偏移量1)
  3. <i>元素的零个子元素之后(节点<i>,偏移量0)
  4. 在"bar"文本节点的字符索引0处(节点"bar",偏移量0)

大多数浏览器实际上不允许所有这些位置,但不幸的是,不同的浏览器有不同的选择。在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;
}