Range对象:Webkit和基于Mozilla的浏览器之间的差异

Tob*_*obi 6 javascript webkit mozilla range

目前,我为使用DOM范围对象(获取和处理用户选择)为Mozilla和基于Webkit的浏览器编写抽象层有些麻烦.

我也试着看看像Rangy这样的框架,但这对我的任务来说似乎很复杂(我不知道在代码中究竟在哪里找到我需要的信息.如果有人能给我一个提示,我将不胜感激!).

我想要的只是这个:

  • 返回对选择开始的文本节点及其偏移量的引用
  • 返回对选择结束的文本节点及其偏移量的引用

到目前为止我的图层看起来像这样:

var SEL_ABSTR = {
get_selection: function(window_object) {
    return window_object.getSelection();
},
get_range: function(selection) {
    return (selection.getRangeAt) ? selection.getRangeAt(0) : selection.createRange();
},
get_range_info: function(range, div_ele) {
    var first_node, start_offset;
    var last_node, end_offset;

    if (range.startContainer == div_ele) {
        // selections affects the containing div
        first_node = div_ele.childNodes[0];
        last_node = first_node;
        start_offset = 0;
        end_offset = first_node.nodeValue.length;
    } else if (range.startOffset == range.startContainer.nodeValue.length && range.endOffset == 0) {
        // known bug in Firefox
        alert('firefox bug');
        first_node = range.startContainer.nextSibling.childNodes[0];
        last_node = first_node;
        start_offset = 0;
        end_offset = first_node.nodeValue.length;
    } else {
        first_node = range.startContainer;
        last_node = range.endContainer;
        start_offset = range.startOffset;
        end_offset = range.endOffset;
    }

    return {
        first_node: first_node,
        start_offset: start_offset,
        last_node: last_node,
        end_offset: end_offset,
        orig_diff: end_offset - start_offset
    };
},
};
Run Code Online (Sandbox Code Playgroud)

我现在已经确定了两个Mozilla漏洞:

  1. 有时当在包含div中选择整个(如果是唯一的)文本节点时,我得到对该div的引用而不是对文本节点的引用.现在我可以处理它并返回对作为文本节点的div的子节点的引用

  2. 有时我会使用offset == prevSibling.length返回对前一个兄弟的引用,并使用offset == 0返回对nextSibling的引用.但是正确的引用将位于中间.我也可以处理这件事.

那么Mozilla还有什么呢?Webkit工作正常!

应该假设DOM范围对象是标准的(我不是在谈论IE,这是另一项任务......)

映入眼帘!


更具体的细节在这里:

这不是对朗伊的批评.如果它听起来像那样我很抱歉.我可以想象处理这些不同的API本身并不容易.

你是对的,我并没有具体说明我要完成的任务.我的结构很简单:我有一个div(属性contenteditable = true)和div中的文本(开头的一个文本节点).

从这个结构开始,现在可以用鼠标选择文本并为其添加属性; 然后,此属性由包含所选文本的范围和分配给表示所选属性的范围的类表示.现在可以再次选择一些文本和属性.如果它是相同的文本和另一个属性,则另一个类将分配给该范围,或者如果该属性已存在则将其删除.如果选择包含多个跨度的文本,它们将被拆分以表达该结构(也许你还记得我7月的帖子).

<div contenteditable="true">
hello I am 
<span class="red">text but I am also <span class="underline">underlined</span></span>
<span class="underline"> also without color</span>
</div>
Run Code Online (Sandbox Code Playgroud)

该算法现在适用于"对称"情况:我可以构建一个复杂的结构,然后向后撤消它.它适用于Safari和Chrome.现在我当然要进一步开发算法.

但是现在我遇到了Mozilla的问题,因为我不理解DOM范围对象的系统:startContainer,endContainer,startOffset,endOffset

在我对我的具体案例的看法中,我只假设一个包含文本节点和跨度的div:

  • startContainer和endContainer始终指向受鼠标选择影响的textnode(没有空跨度,它们总是包含其他跨度或textnode),标记整个选择的开头和结尾
  • startOffset和endOffset指示选择在textnode开头和结尾的位置

在上面的发布代码中,我发现了两个案例,其中Mozilla的行为与webkit不同.

因此,如果我知道Mozilla DOM-range的规则,我可以在我的层中将其整合,以便webkit和Mozilla的行为相同.

非常感谢您的回答.

Tim*_*own 3

没有规则规定选择边界必须用文本节点来表达。<img>例如,考虑仅包含元素的元素内的选择。所以,你所说的 Mozilla 中的 bug 根本不是 bug;而是 bug。事实上,WebKit 的选择处理比 Mozilla 的. 然而,您观察到浏览器在认为选择边界位于文本节点末尾时的精确位置上有所不同,这是有效的,并且确实使事情变得复杂。处理它的最佳方法实际上取决于您想要做什么,这从您的问题中并不清楚。

如果您想要纯粹根据元素文本内容内的字符偏移量来选择边界,则可以执行此操作(尽管出于链接答案中列出的原因,我通常建议不要这样做)。

最后,作为 Rangy 的作者,我想指出它基于浏览器实现的相同 API(DOM Range 和 Selection),所以我想说它并不比这些 API 更复杂或更简单。参考:

  • 选择(正在进行中)
  • DOM 2 Range(由所有主要浏览器的当前版本实现)
  • DOM4 Range(DOM 2 Range 的后续版本,正在进行中)