如何在javascript中遍历选定范围内的每个节点?
Posted
技术标签:
【中文标题】如何在javascript中遍历选定范围内的每个节点?【英文标题】:How to iterate over every node in a selected range in javascript? 【发布时间】:2016-05-30 07:03:29 【问题描述】:在 javascript 中实现富文本编辑器时,我需要对选定范围内的每个文本节点应用一些更改。 Range 对象提供接口来获取选定范围的startContainer
、endContainer
、startOffset
、endOffset
。如何遍历其间的每个 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_REJECT
和 NodeFilter.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
将为您提供包含该范围的节点。如果它为您提供了一个文本节点,那么这是您范围内的唯一节点。
如果它给你一个元素,你可以使用NodeIterator
或el.querySelectorAll('*')
来获取其中的节点。
并非所有这些都在您的范围内,因此请使用range.intersectsNode(el)
进行确认。
【讨论】:
Range.intersectsNode()
不支持 IE(最多并包括 11 个):( 同样Selection.containsNode()
。以上是关于如何在javascript中遍历选定范围内的每个节点?的主要内容,如果未能解决你的问题,请参考以下文章
如何通过javascript获取textarea元素内的选定文本?