如何在javascript中遍历选定范围内的每个节点?

Posted

技术标签:

【中文标题】如何在javascript中遍历选定范围内的每个节点?【英文标题】:How to iterate over every node in a selected range in 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?

【问题讨论】:

an example on accessing the range DOM 能让你快速上手吗? @RogierSpieker 这为我指明了正确的方向,谢谢! 【参考方案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_REJECT 的 NodeFilter.acceptNode() 文档不正确。

【讨论】:

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

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

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

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

【讨论】:

Range.intersectsNode() 不支持 IE(最多并包括 11 个):( 同样Selection.containsNode()

以上是关于如何在javascript中遍历选定范围内的每个节点?的主要内容,如果未能解决你的问题,请参考以下文章

如何通过javascript获取textarea元素内的选定文本?

javascript 怎么输出指定输入范围内的质数

选定范围内的VBA验证

遍历范围,将字符串附加到每个

如何在分段控制器内的 tableView 中保存选定行的状态?

每个内的 jQuery 变量范围