resultType类型_resultType类型


这是我首次在知乎写文章。我决定要这么做,因为:

  1. Web 编辑器开发所需知识点犹如串联,体系庞大内容复杂
  2. 现有的文章让我犯困,没有学习乐趣

所以我试图通过一边阅读文章和文档进行学习,一边写关于学习对象的文章。我期望通过这样的方式,让我能够稳定掌握 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 对象要少许多,但仍能诠释两者的特点。比如说,它们都有开始节点、结束节点。