登录
Range 接口表示一个包含节点与文本节点的一部分的文档片段,这个文本片段可以是空的、纯文字、成对的 dom 节点。
Range 是一个范围,基于 Dom 节点的范围,如果修改了 Range 范围中的 Dom,Range 的范围也会自动调整,如果删除了 Range 内的所有 Dom,相当于 Range 的开始和结束位置相等了。
Range 和 Selection 配合使用效果更佳。
一个 Range 对象有一下几个只读属性:
用于定位和调整 range 范围
设置 Range 的起点。
语法:range.setStart(startNode, startOffset)
注意:如果 Range 开头和结尾并不是成对的 dom 节点,则会自动删掉多余的部分。
<!DOCTYPE html>
<body>
<div class="box">
asdf1
<div class="box_1">小盒子1</div>
<div class="box_2">小盒子2</div>
<div class="box_3">小盒子3</div>
<div class="box_4">小盒子4</div>
</div>
</body>
<script>
let domBox = document.querySelector('.box')
// 先打印一下 dom 看一下
for (let i = 0; i < domBox.childNodes.length; i++) {
let child = domBox.childNodes[i]
// 文本节点, 打印文本内容
if (child.nodeType === 3) console.log(i, child.data)
// 元素节点,打印 dom 的 string
else console.log(i, child.innerHTML)
}
console.log('------ 隔离线 ------')
// 创建 Range
let docuRange = document.createRange()
docuRange.setStart(domBox, 0)
docuRange.setEnd(domBox, 4)
// 打印 Range 的内容,主要看一下 Range 包含的范围
console.log(docuRange.cloneContents()) // 获取 range 的内容进行打印
</script>
打印结果如下,可见 setStart 是设置 startNode 这个节点的内部某一处作为起始的。
startOffset 是 childNodes 的索引值,指的是第几个子节点的开头位置。
设置 Range 的终点,类似设置起始位置的 Range.setStart
语法:range.setStart(startNode, startOffset)
以其它节点为基准,设置 Range 的起点。
语法:range.setStartBefore(referenceNode)
以其它节点为基准,设置 Range 的起点。
语法:range.setStartAfter(referenceNode);
以其它节点为基准,设置 Range 的终点。
语法:range.setEndBefore(referenceNode)
以其它节点为基准,设置 Range 的终点。
语法:range.setEndAfter(referenceNode)
使 Range 直接选中某个节点作为 Range 的范围。
语法:range.selectNode(referenceNode)
使 Range 直接选中某个节点的内容,作为 Range 的范围。
语法:range.selectNode(referenceNode)
将 Range 折叠至其端点(boundary points,起止点,指起点或终点,下同)之一。
通俗来说,就是清空 Range,但 Range 表示一个范围,即使是空的,也只是表示他的开始和结束是同一个位置。
而开始和结束是同一位置,这个位置就是由参数 toStart 决定的。
折叠后的 Range 的 collapsed 属性为 true,表示起始位置和终止位置是相同的。
语法:range.collapse(toStart)
可以从 Range 中获得节点,改变 Range 的内容。
返回一个包含 Range 中所有节点的文档片段。
这个文档片段是对文档 Dom 的拷贝,获取后,再修改 Range 范围和文档 Dom,不会影响该文档片段。
使用DOM事件添加的事件侦听器在提取期间不会保留。
HTML属性事件将按Node.cloneNode()方法的原样保留或复制。
HTML id属性也会被克隆,如果提取了部分选定的节点并将其附加到文档中,则可能导致无效的文档。
let range = document.createRange();
range.selectNode(document.getElementsByTagName("div"));
let documentFragment = range.cloneContents();
document.body.appendChild(documentFragment);
从文档中移除 Range 包含的内容,删除 Range 范围中的所有 Dom,Range 的范围也自动调整了。
语法:range.deleteContents()
把 Range 的内容从文档树移动到一个文档片段中。
功能类似于前面的 Range.cloneContents(),但 cloneContents 是返回拷贝的文档片段,而这个是移动。
且因为是移动,页面文档中的 Dom 也就因为移走而消失了,Range 的范围也会自动更新,效果类似于 Range.deleteContents()。
所以整体来看:Range.extractContents() === Range.cloneContents() + Range.deleteContents()
语法:documentFragment = range.extractContents();
在 Range 的起点处插入一个 Dom 节点。
新节点是插入在 Range 开始位置之后,也就是范围内所有节点之前。
如果新节点是一个文档片段,则插入文档片段的子节点(就是文档片段内部的 Dom 节点)。
语法:range.insertNode(newNode);
将 Range 的内容移动到一个新的节点中,并将新节点放到这个范围的起始处。
这个方法与 newNode.appendChild(range.extractContents()) + range.insertNode(newNode) 等价。
应用以后,newNode 包含在 range 的边界点中。
然而,如果 Range 断开了一个非 Text 节点,只包含了节点的其中一个边界点,就会抛出异常。
也就是说,不像上述的等价方法,如果节点仅有一部分被选中,则不会被克隆,整个操作会失败。
语法:range.surroundContents(newParent); newParent:一个包含内容的 Dom 节点。
比较两个 Range 的端点。
语法:compare = range.compareBoundaryPoints(how, sourceRange);
克隆一个 Range, 克隆的对象是复制过来的,而非引用,所以这两个对象双方各自做出的改变,都不会影响另一方。
语法:clone = range.cloneRange()
不执行任何操作,只将 Range 从使用状态中释放,改善性能,它用于禁用 Range对象并允许浏览器释放关联的资源,该方法已保留用于兼容性。
语法:range.detach();
把 Range 中的 Dom 节点中的文字内容返回(包括换行和空格等)。
语法:text = range.toString();