序
这是我首次在知乎写文章。我决定要这么做,因为:
- Web 编辑器开发所需知识点犹如串联,体系庞大内容复杂
- 现有的文章让我犯困,没有学习乐趣
所以我试图通过一边阅读文章和文档进行学习,一边写关于学习对象的文章。我期望通过这样的方式,让我能够稳定掌握 Selection 对象的基本知识。
该类型文章的服务对象通常只有我自己,之所以发在知乎也是为了有效保存文章。不过如果你认为文章难以阅读,可以向我提出建议,我会尽量尝试改善。
什么是 Selection 对象
一个 Selection 代表了用户在网页中选择内容的集合。
详细地说,用户按住鼠标,随后拖动鼠标,再松开鼠标——从这个过程中创建的选区就是 Selection 集合中的一个(大概是这样吧,Selection 和 Range 应该是包含关系,Range 代表一个选区, Selection 代表所有选区)。
在了解 Selection 对象的基本属性前,我需要先学习几个术语:
- anchor 锚点:一个选区的起始,也代表鼠标按下瞬间,光标所在的位置。
- focus 焦点:一个选区的末尾,也就是鼠标松开瞬间,光标所在的位置。
- range 范围:选区连续的部分,指的是选区的起始到末尾的地方。
由上面三个术语,我基本明白一个选区是如何诞生的:选区有一个起始的位置,还有一个结束的位置;它开始的地方叫 anchor ,它结束的地方叫 focus ,它从开始到结束的部分叫做 range 。
从 anchor 和 focus 的位置能够反推用户选择文字的方向:
- 我从右往左选择一段文字,那么 anchor(起始点)在focus(结束点)的右边;
- 我从左往右选择一段文字,那么 anchor(起始点)在focus(结束点)的左边;
- 我点击段落中某一个位置,而不是选择一段文字,那么 anchor(起始点)和 focus(结束点)的位置重叠。
创建一个 Selection 对象
现在有一个段落A:
<p>A placeholder can be really <b>cool</b> but should it? I doubt that.<br/></p>
我在段落A中,从左往右选择了一段文字:
can be
之后,我通过 window.getSelection() 方法,获取到以下内容:
{
anchorNode: text
anchorOffset: 14
baseNode: text
baseOffset: 14
extentNode: text
extentOffset: 20
focusNode: text
focusOffset: 20
isCollapsed: false
rangeCount: 1
type: "Range"
__proto__: Selection
}
这是一个 type 值为 "range" 的的 Selection 对象,包含了我刚选择的选区信息——我把它命名为 selectionA。
待会儿我会将selectionA的主要属性进行一番解析。
文本节点的分割
在了解 Selection 的属性之前,我们还需要学习文本节点的分割原理,因为文本节点是我们理解 Selection 属性的基础。
这是上面定义的段落A:
<p>A placeholder can be really <b>cool</b> but should it? I doubt that.<br/></p>
在根据标签进行分割后,会得出这些节点:
节点1 "A placeholder can be really "
节点2 "cool"
节点3 "but should it? I doubt that."
它们就是文本节点,稍微理解一下就能明白其中的逻辑。
需要注意的是,虽然文本节点是 Text 对象的主要内容,但不是唯一内容。比如,下面是一个代表节点1的 Text 对象:
{
assignedSlot: null
baseURI: "http://localhost:8080/"
childNodes: NodeList []
data: "A placeholder can be really "
firstChild: null
isConnected: true
lastChild: null
length: 28
nextElementSibling: b
nextSibling: b
nodeName: "#text"
nodeType: 3
nodeValue: "A placeholder can be really "
ownerDocument: document
parentElement: p
parentNode: p
previousElementSibling: null
previousSibling: null
textContent: "A placeholder can be really "
wholeText: "A placeholder can be really "
}
可以看出,Text 对象内其实包含许多有的没的属性。所以,我们在具体操作 Text 对象时,还需要了解它的各种属性。当然这个之后再说,当务之急是了解整个 Selection 对象的大体情况。
Selection 对象的基本属性
anchorNode
anchorNode 是一个 Text 对象,它代表 anchor(起始点)所在的文本节点对象。
我知道段落A经过分割后,得出下列节点:
节点1 "A placeholder can be really "
节点2 "cool"
节点3 "but should it? I doubt that."
在 selectionA 中,我选择了这段内容:
can be
这串字符所在的文本节点为节点1。我可以暂时这么理解:
selectionA.anchorNode = 节点1
当然,selectionA.anchorNode 是一个 Text 对象而不只是简单的 String 对象。为什么我说可以暂时将 selectionA.anchorNode 与节点1划上等号呢?
selectionA.anchorNode 有个重要的属性:
{
...
textContent: "A placeholder can be really "
...
}
这个属性是 selectionA.anchorNode的主要属性,而可以看出,selectionA.anchorNode.textContent 的内容等于节点1的内容。所以我暂时这样理解是没有错的,这有助于我理解整个 Selection 对象的内容。
selectionA.anchorNode 包含了不少属性,但我们现在需要从整体理解 Selection 对象,还没到详细剖析的时候。所以现在,我们只需要知道 selectionA.anchorNode ,也就是起始文本节点,代表了什么,以及文本节点们是如何被划分的,这就足够了。
anchorOffset
anchorOffset
我知道 selectionA.anchorNode 的主要内容为:
A placeholder can be really
而 selectionA.anchorOffset 的值为:
14
所以 anchor(起始点)在 selectionA.anchorNode 内容的从左往右数第 15 位字符的左侧(从0开始数):
A placeholder |can be really
看,它在竖线所指的地方。
focusNode
focusNode 是一个 Text 对象,它代表 focus(结束点)所在的文本节点对象。
我知道段落A经过分割后,得出下列节点:
节点1 "A placeholder can be really "
节点2 "cool"
节点3 "but should it? I doubt that."
在 selectionA 中,我选择了这段内容:
can be
由于所选内容没有跨越标签, selectionA.focusNode 的内容和 selectionA.anchorNode 的内容一样,等于节点1。
这个属性由于上面进行了类似的解析,所以没有太多可以说的内容。
focusOffset
focusOffset
该属性的意义和 selectionA.anchorOffset 是类似的,只不过 selectionA.focusOffset 属性代表的是 focus(结束点)的文本节点偏移量。
已知节点A内容为:
A placeholder can be really
而 selectionA.focusOffset 的值为:
20
则该位置在竖线位置,也就是从0开始,从左往右第20位字符的左侧:
A placeholder can be| really
isCollapsed
isCollapsed
当我只是点击段落的某个位置,而不是选择一个区间,那么我获取到的 Selection 对象,它的anchor(起始点)和focus(结束点)在同一个位置,则这时候, isCollapsed 属性的值为:
true
对于selectionA,它的 range 是有长度的,则 selectionA.isCollapsed的值为
false
rangeCount
rangeCount 是一个数值,它表示 Selection 对象获取到多少个 range 。
通常情况下, rangeCount 为0或者1,因为浏览器一般不允许用户选择多个 range 。当用户没有选择任何区域,则 rangeCount 值为:
0
对于selectionA,它的 range 只有一个,则 selectionA.rangeCount 的值为:
1
type
type 是一个字符串,它表示 Selection 对象的类型。
当用户选取了一个范围,则 type 的值为
Range
当用户点击了某处而非选取了一个范围,则 type 的值为
Caret
对于selectionA,它是一个范围,则 type 的值为
Range
总结
学到这里,我基本了解了 Selection 对象的基本属性,但在运用方面、概念方面,我还不是很明白。
Selection 对象和 Range 对象在我看来是属性很相似的两种对象,甚至 Range 对象的基础属性都比 Selection 对象要少许多,但仍能诠释两者的特点。比如说,它们都有开始节点、结束节点。