【问题标题】:How to iterate over every node in a selected range in javascript?如何在javascript中遍历选定范围内的每个节点?
【发布时间】:2016-05-30 07:03:29
【问题描述】:

在 javascript 中实现富文本编辑器时,我需要对选定范围内的每个文本节点应用一些更改。 Range 对象提供接口来获取选定范围的startContainerendContainerstartOffsetendOffset。如何遍历其间的每个 DOM 节点?

var selection = window.getSelection();
var range = selection.getRange(0);
// How can I iterate over every node within the range?

【问题讨论】:

标签: javascript html textselection


【解决方案1】:

按照建议,您可以使用NodeIterator 走进range.commonAncestorContainer

这是一个sn-p:

var _iterator = document.createNodeIterator(
    range.commonAncestorContainer,
    NodeFilter.SHOW_ALL, // pre-filter
    {
        // custom filter
        acceptNode: function (node) {
            return NodeFilter.FILTER_ACCEPT;
        }
    }
);

var _nodes = [];
while (_iterator.nextNode()) {
    if (_nodes.length === 0 && _iterator.referenceNode !== range.startContainer) continue;
    _nodes.push(_iterator.referenceNode);
    if (_iterator.referenceNode === range.endContainer) break;
}

您应该使用NodeFilter.SHOW_ALL,因为您的范围可以包含多个nodeTypes。如果你知道你在选择什么,你可以检查this reference正确选择NodeFilter


编辑:我还想指出document.createTreeWalker()

主要区别在于 document.createTreeWalker() 允许您的 acceptNode 过滤器返回 NodeFilter.FILTER_REJECTNodeFilter.FILTER_SKIP 两者之间的差异。

引用NodeFilter docs

FILTER_REJECT:

当一个节点应该被拒绝时由 NodeFilter.acceptNode() 方法返回的值。 对于 TreeWalker,子节点也被拒绝。对于 NodeIterator,此标志与 FILTER_SKIP 同义。

Ps:NodeFilter.FILTER_REJECTNodeFilter.acceptNode() 文档不正确。

【讨论】:

  • 我可能错了,但我认为不使用 NodeFilter.SHOW_ALL 可能会导致第一个条件总是评估为 false,因为如果它被过滤掉,referenceNode 可能永远不会等于 startContainer。
【解决方案2】:

range.commonAncestorContainer 将为您提供包含该范围的节点。如果它为您提供了一个文本节点,那么这是您范围内的唯一节点。

如果它给你一个元素,你可以使用NodeIteratorel.querySelectorAll('*') 来获取其中的节点。

并非所有这些都在您的范围内,因此请使用range.intersectsNode(el) 进行确认。

【讨论】:

  • Range.intersectsNode() 不支持 IE(最多并包括 11 个):( 同样Selection.containsNode()
猜你喜欢
  • 2022-09-29
  • 1970-01-01
  • 1970-01-01
  • 2021-04-10
  • 1970-01-01
  • 2017-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多