前言:本文介绍Web API中的Range接口和Selection接口的应用,通过许多demo理解它们属性和方法的定义,相对于官网陈述性表达,介绍了很多实际应用。
一、Range对象
Range是Web Api的接口,Range 接口表示一个包含节点与文本节点的一部分的文档片段。
(一)创建Range有以下几种方式
- Document.createRange()
- new Range()
(二)属性介绍
range对象有以下几个方法,先大致看一下基本的定义,后续的实例中会详细的讲述它们的含义和用法。
- Range.collapsed 起始位置和结束位置是否重合。
- Range.commonAncestorContainer 目标节点的公共的祖先节点。
- Range.endContainer Range对象结束位置所属节点。
- Range.endOffset Range 结束位置在 Range.endContainer 中的偏移值的数字。
- Range.startContainer Range 对象开始位置所属节点。
- Range.startOffset Range 在 startContainer 中的起始位置的数字。
(三)方法介绍
上述的属性,只看定义是没有办法真正理解的,需要搭配下面的方法来理解真正的用途。
- setStart()、setEnd()、cloneContents()方法
- setStart()、setEnd()方法
分别用来设置Range对象的起始位置和结束位置,接收两个参数:
- 父节点
- 偏移量 不小于0的整数,表示索引值,表示从父节点的指定索引的子节点作为起始或结束节点
- cloneContents()返回一个Range 中所有的 Node 对象的副本。
- 应用实例:
- 代码:
<body>
<!--注意:换行或空格都会被算作range的child,影响offset的设定-->
<div id="content1"><h1>content1:range与selection</h1><h1>content1:今日份学习</h1><h1>content1:工作工作</h1></div>
<div id="content2"><div>content2:五一之后上班的第一天:😴</div><div>content2:干巴得</div><div>content2:真呀真高兴</div></div>
<script>
const content1 = document.getElementById('content1')
const content2 = document.getElementById('content2')
const range = new Range();
// 起始位置的父元素设置为content1,从索引为1的子节点开始,包括起始节点
range.setStart(content1, 1)
// 结束位置的父元素设置为content2,从索引为1的子节点结束,不包括结束节点
range.setEnd(content2, 1)
const copy = document.createElement('div')
copy.style.color = 'purple'
copy.appendChild(range.cloneContents())
document.body.appendChild(copy)
console.log(range)
</script>
</body>
- 效果:
- element:
- 控制台查看range:
- setStartBefore()、setStartAfter()、setEndBefore()、setEndAfter()
- 方法定义:
接收一个node节点作为参数
setStartBefore(node):起始位置在该节点的前面,range包含node
setStartAfter(node):起始位置在该节点的后面,range不包含node
setEndBefore(node):结束位置在该节点的前面,range不包含node
setEndAfter(node):结束位置在该节点的后面,range包含node - 实例
- 代码
<body><div id="content1"><h1>content1:range与selection</h1><h1>content1:今日份学习</h1><h1>content1:工作工作</h1></div><div id="content2"><div>content2:五一之后上班的第一天:😴</div><div>content2:干巴得</div><div>content2:真呀真高兴</div></div>
<script>
const content1 = document.getElementById('content1')
const content2 = document.getElementById('content2')
const range = new Range();
// 起始位置在content1之前
range.setStartBefore(content1)
// 起始位置在content2之后
range.setEndAfter(content2)
const copy = document.createElement('div')
copy.style.color = 'purple'
copy.appendChild(range.cloneContents())
document.body.appendChild(copy)
console.log(range)
</script>
</body>
- 效果
为了避免换行影响range对象的offset,body体内的元素都不换行。range包括content1和content2 - 控制台查看range对象:
- 修改两行代码:
range.setStartAfter(content1)
range.setEndBefore(content2)
- selectNode、selectNodeContents
- selectNode接收一个node作为参数,将range的范围设置为从这个node外部起始到这个node外部结束。range包含整个node及其内容
- 代码
range.selectNode(content1)
- 查看元素:
- range对象:
- selectNodeContents接收一个node作为参数,将range的范围设置为从这个node内部起始到这个node内部结束。range只包含node内部的内容
- 代码
range.selectNodeContents(content1)
- 查看元素:
- range对象:
- insertNode在range的起始位置插入元素
- 代码
range.selectNode(content1)
const copy = document.createElement('div')
copy.style.color = 'purple'
copy.appendChild(range.cloneContents())
range.insertNode(copy)
- 效果:
- range对象包含插入的这个节点
- getClientRects()方法返回一个 DOMRect 对象列表,表示 range 在屏幕上所占的区域。
- 代码:
console.log(range.getClientRects())
- 控制台查看
获取range包含的所有节点的位置信息
- collapse()方法接收一个boolean值,可以折叠range,即将选中文本变为光标闪烁形式。传递true时光标会在range的起始位置,传递false时光标会在range的结束位置。不管是true还是false,range的collapse属性都会变成true。
二、Selection对象
Selection 对象表示用户选择的文本范围或插入符号的当前位置。它代表页面中的文本选区,可能横跨多个元素。
(一)创建selection对象:window.getSelection()
其中没有标注的几个属性即将被废弃。
(二)常用方法
- Selection.getRangeAt() 接收一个index索引值作为参数,返回一个range对象;主流浏览器一个selection只有一个range,所以这里传0即可。
- 代码
<div id="content1">content:range与selection<h1>红红火火恍恍惚惚</h1></div>
<script>
const content1 = document.getElementById('content1')
content1.addEventListener('click', e => {
const selection = window.getSelection()
console.log(selection.getRangeAt(0))
})
</script>
- 选中几个文字,查看控制台输出
- Selection.removeRange()移除一个range
- 以下代码可以实现禁止光标和选中文字。
content1.addEventListener('click', e => {
const selection = window.getSelection()
selection.removeRange(selection.getRangeAt(0))
})
- Selection.collapse() 方法可以收起当前选区到一个点。接收两个参数,会把焦点放在父节点中对应索引的子节点的前面。如果该父节点是可编辑的,能看到光标闪烁。
参数一:父节点
参数二:偏移量,表示索引
- 代码
<div id="content1" contenteditable="true">content:range与selection<h1>红红火火恍恍惚惚</h1></div>
<script>
const content1 = document.getElementById('content1')
content1.addEventListener('click', e => {
const selection = window.getSelection()
selection.collapse(content1,1)
})
</script>
- 选中文字之后,光标会在content1中索引为1的子节点的开头闪烁
- Selection.collapseToStart()、Selection.collapseToEnd()不需要接收参数。表示取消当前选区,并且把光标放在选区的起始位置/结束位置。以collapseToStart为例,选中”恍恍惚惚“后,光标会放在这里:
- Selection.containsNode() 接收两个参数,返回布尔值,表示选区是否包含节点。
参数一:节点
参数二:是否部分被包含;为true时只需包含节点的一部分就返回true,为false时必须包含节点的全部才会返回true
selection.containsNode(document.querySelector('h1'),true)
- Selection.extend() 接收两个参数,可以扩展选区。选区的起始位置不变,结束位置变为父节点中规定索引值的子节点的前面
参数一:父节点
参数二:偏移量,索引值
- 代码:
selection.extend(content1,1)
- 效果
在第一行选中:
在第二行选中:
- Selection.selectAllChildren()接收一个节点作为参数,选中该节点的所有子节点并且清除之前的选区
- 代码
selection.selectAllChildren(content1)
- 在div中点击或者选中文字可以实现全选的效果
- Selection: setPosition()接受两个参数,表示把焦点放在指定的节点中的指定索引值的子节点前面;同Selection.collapse()。
参数一:父节点
参数二:偏移量,子节点索引值 - Selection: toString() 返回选区中的文本
- 代码
console.log(selection.toString())