那些被忽略但很好用的 Web API / Selection

选你所爱,爱你所选。

在浏览网站时,反白(或称反蓝)其实是一个非常常见的动作,不管是要强调目前的阅读区域或是想要复制某个段落,使用者都会透过游标进行反白,而 Selection API 就是针对反白的选取区块进行操作。


Selection

Selection 本身是一个物件,它代表的是目前使用者所选的文本范围,或是「输入游标」插入的位置,这文本范围可能会涵盖到多个元素,也可能会坍缩在一个点(也就是没有选取到任何文本),而这整个选取范围又包含了几个专有术语:

https://ithelp.ithome.com.tw/upload/images/20210924/20125431FHzmnBDFYt.png

你该知道:

  1. anchor 有可能在 focus 前面也有可能在 focus 後面,这取决於你拖曳游标的方向。
  2. range 可能会横跨多个节点,但 anchor 和 focus 只会存在在最初与最後的节点当中。

# Window.getSelection

如果想要取得目前选取范围的 Selection 物件,那只要呼叫这个 method 就可以了:

let selectionObj = window.getSelection();
console.log(selectionObj); // Selection 物件

 

# Selection.anchorNode

取得了 Selection 物件後我们就可以读取它本身的一些属性了,而 anchorNode 就是其中之一,它会给我们当初反白时 anchor 位置所在的节点。

let selectionObj = window.getSelection();
console.log(selectionObj.anchorNode); // 一个文字节点

 

# Selection.anchorOffset

知道 anchor 所在节点後,还可以透过 anchorOffset 来知道 anchor 点下的位置距离节点开头相差了几个字:

let selectionObj = window.getSelection();
console.log(selectionObj.anchorOffset); // 一个 number,代表与节点开头相差了几个字

 

# Selection.focusNode

当然了,可以知道 anchor 的位置,自然也能知道 focus 的位置。

let selectionObj = window.getSelection();
console.log(selectionObj.focusNode); // 一个文字节点

 

# Selection.focusOffset

以此类推,有 focusNode 就也会有 focusOffset

let selectionObj = window.getSelection();
console.log(selectionObj.focusOffset); // 一个 number,代表与节点开头相差了几个字

 

# Selection.toString

那除了一些唯读属性之外呢,Selection 物件有有一些自身的 methods 可以使用,其中最简单也最重要的自然就是取得所选范围的文本内容,这时候只要呼叫 toString 就可以了:

let selectionObj = window.getSelection();
console.log(selectionObj.toString()); // 所选范围的文本内容

 

# Selection.collapse

collapse 是个比较特别的 method,它会让 Selection 坍缩到只剩下一个点,也就是从一个反白区块变成只剩下一个闪烁的输入游标在画面上。

collapse 有两个参数可以传入,第一个是你想坍缩 Selection 到哪一个节点上,第二个参数则是你要坍缩在该节点上的第几个位置。

<div contenteditable="true">这里的文字可以编辑</div>
<button>collapse</button>
<script>
  const button = document.querySelector("button");
  button.addEventListener("mousedown", function(e){
    e.preventDefault();
  })
  button.addEventListener("click", function(){
    const selection = window.getSelection();
    // 将选取范围坍缩在 anchor 所在节点的第十个字
    selection.collapse(selection.anchorNode, 10);
  })
</script>

要注意,尽管你看不到闪烁的游标,但其实游标还是被放到了你 focus 或 collapse 的位置。而如果你将元素改为 contenteditable,你就可以清楚看到游标了。

 

# Selection.extend

另一个和 collapse 很像的是 extend,它会让 anchor 保持不变并移动 focus,也就是说你可以改变反白的区域。它的参数也和 collapse 一样,第一个是你要将 focus 移动到哪个节点,第二个则是要移动到该节点的第几个字。

<div contenteditable="true">这里的文字可以编辑</div>
<button>extend</button>
<script>
  const button = document.querySelector("button");
  button.addEventListener("mousedown", function(e){
    e.preventDefault();
  })
  button.addEventListener("click", function(){
    const selection = window.getSelection();
    // 将 focus 移动到跟 anchor 一样的位置,此时 Selection 会是坍缩的
    selection.extend(selection.anchorNode, selection.anchorOffset);
  })
</script>

 

# Selection.selectAllChildren

这个 method 算是非常好用的,它可以够传入一个元素节点来指定目前的选取范围。如果你传的是整个 document.body 那就相当於是全选整个网页。

<div>
  Lorem ipsum dolor sit amet consectetur adipisicing elit.
</div>
<script>
  const div = document.querySelector("div");
  const selection = window.getSelection();
  selection.selectAllChildren(div); // div 中的内容将整个被反白起来
</script>

 

# Selection.deleteFromDocument

deleteFromDocument 可以帮我们将目前选取的区块从整个文件中删除,当然,他指的是目前浏览的页面,并不会连同你的程序码一并删除。

<div>
  Lorem ipsum dolor sit amet consectetur adipisicing elit.
</div>
<script>
  const div = document.querySelector("div");
  const selection = window.getSelection();
  // 我们将 div 中的内容整个反白起来後删除了
  selection.selectAllChildren(div);
  selection.deleteFromDocument(); 
</script>

 

# Document:selectionchange Event

最後,除了主动针对 Selection 物件进行操作外,Document 本来还可以监听 selectionchange 的事件,当今天文件中的选取范围有了更动,该事件就会触发,并执行我们指定的 Callback。

document.addEventListener("selectionchange", () => {
  // 讲选取起来的文本内容设定到指定的容器中
  document.querySelector("#text").textContent = window.getSelection().toString();
});

 

相信看完今天的内容,你可能会觉得 Selection API 功能似乎蛮齐全的,但好像也不知道要拿来做什麽应用,但其实只要搭配昨天的 DesignMode,我们就可以制作一个简易的文章编辑器了,不过等到明天的 Clipboard 一并介绍完後,我们再来实际动手做,届时各位就会知道 Selection API 其实是蛮好玩的。


<<:  JS 09 - 类别函式

>>:  [C 语言笔记--Day13] Pointers to Functions

sql 记录运作时间

用了多少时间 记录在变数的方式 declare @BTIME datetime declare @E...

Day 2 - 谈谈伦理骇客

出於书本 Chapter 1. Introduction to Ethical Hacking 骇客...

Day 22 - Spring Boot & Interceptor

Interceptor 拦截器 在许多的Java Web 框架都有实现Interceptor 的方法...

【程序】给 23 - 28 岁的你的一封信 转生成恶役菜鸟工程师避免 Bad End 的 30 件事 - 29

来到了铁人赛的29天,扣除掉最後一集的心得,今天算是最後一个主题。 今天的影片和以往不太一样,我事...

<Day14> Ticks — 取得期货(Futures)逐笔成交资料

● 这章来示范如何取得期货(Futures)的ticks 回顾上一章,我们学会如何取得股票的tick...