最近在看mdn,很早之前就了解点文本选区,但是介于他API太多,当时就劝退自己了,这周闲下来梳理下。
getSelection()
返回一个 Selection
对象,表示用户选择(当前点击)的文本范围或光标的当前位置。它代表页面中的文本选区,可能横跨多个元素。文本选区由用户拖拽鼠标经过文字而产生。
我们来看看他提供的属性和方法吧。
getSelection()
属性
-
anchorNode
返回该选区起点所在的节点。 -
anchorOffset
返回一个数字,其表示的是选区起点在anchorNode
中的位置偏移量。- 如果
anchorNode
是文本节点,那么返回的就是从该文字节点的第一个字开始,直到被选中的第一个字之间的字数(如果第一个字就被选中,那么偏移量为零)。 - 如果
anchorNode
是一个元素,那么返回的就是在选区第一个节点之前的同级节点总数。(这些节点都是anchorNode
的子节点)
- 如果
-
focusNode
返回该选区终点所在的节点。 -
focusOffset
返回一个数字,其表示的是选区终点在focusNode
中的位置偏移量。 -
如果
focusNode
是文本节点,那么选区末尾未被选中的第一个字,在该文字节点中是第几个字(从 0 开始计),就返回它。选区起始和终止都在一个节点上时,他就是anchorOffset
+ 当前节点选中的文字个数 -
如果
focusNode
是一个元素,那么返回的就是在选区末尾之后第一个节点之前的同级节点总数。 -
isCollapsed
返回一个布尔值,用于判断选区的起始点和终点是否在同一个位置。表示当前是否有任何文本被选中 -
rangeCount
返回该选区所包含的连续范围的数量。chrome禁止使用连续选区。 -
type
描述当前选择的类型。None
: 当前没有选择。Caret
: 选区已折叠(即未处于选中状态)。Range
: 选择的是一个范围。
方法
getRangeAt(index)
获取指定索引的 Range
对象(index < rangeCount)。chrome永远是0。
addRange(range)
将 Range
对象添加到当前选择。由于chrome不能连续选区,所以这个api目前想到的唯一用处就是修改选区。
js 代码解读复制代码// 选中某个元素的全部文本
function selectElementText(element) {
const range = document.createRange();
range.selectNodeContents(element);
const selection = window.getSelection();
// 移除上次选区
selection.removeAllRanges();
selection.addRange(range);
}
removeAllRanges(), removeRange(range)
removeAllRanges()
清除所有选择范围。removeRange(range)
移除某个指定选区。传入对应的选区对象。
collapse(node, offset)
可以收起当前选区到一个点。即取消当前选区,然后聚焦到对应的位置。
js 代码解读复制代码/* 将光标收起到文档 body 的开头 */
var body = document.getElementsByTagName("body")[0];
window.getSelection().collapse(body, 0);
collapseToEnd()
取消当前选区,并把光标定位在原选区的最末尾处,如果此时光标所处的位置是可编辑的,且它获得了焦点,则光标会在原地闪烁。
collapseToStart()
取消当前选区,并把光标定位在原选区的最开始处,如果此时光标所处的位置是可编辑的,且它获得了焦点,则光标会在原地闪烁。
containsNode(node, partlyContained)
判断指定的节点是否被选中。参数二表示是否是部分包含。
js 代码解读复制代码 /* 检查 body 中是否有节点被选中 */
window.getSelection().containsNode(document.body, true)
deleteFromDocument()
直接在页面中删除选区中的内容。
js 代码解读复制代码window.getSelection().deleteFromDocument()
empty()
删除选中的区域。
js 代码解读复制代码window.getSelection().empty()
extend(node, offset)
扩展选择到新位置。
js 代码解读复制代码// node 焦点应该被拓展到的区域。
// offset 在node中的偏移。
window.getSelection().extend($0, 1)
modify(alter, direction, granularity)
改变当前选区或光标位置。
-
alter
改变类型。传入"move"
来移动光标位置,或者"extend"
来扩展当前选区。 -
direction
调整选区的方向。你可以传入"forward"
或"backward"
来根据选区内容的语言书写方向来调整。或者使用"left"
或"right"
来指明一个明确的调整方向。 -
granularity
调整的距离颗粒度。可选值有"character"
、"word"
、"sentence"
、"line"
、"paragraph"
、"lineboundary"
、"sentenceboundary"
、"paragraphboundary"
、"documentboundary"
。
js 代码解读复制代码var selection = window.getSelection();
selection.modify("extend", "forward", "word"); // word 对于汉字会自己组词偏移
selectAllChildren(parentNode)
把指定元素的所有子元素设为选中区域,并取消之前的选中区域。
setBaseAndExtent(anchorNode, anchorOffset, focusNode, focusOffset)
用来选中并设置在两个特定的 DOM 节点中文本选中的范围,并且选中的任何内容都位于两个节点之间。
anchorNode
选中内容的开始节点anchorOffset
选中范围内起点位置在锚节点下第几个子节点的位置。例如,如果是值为 0 的话,整个节点都是被选中的。如果值为 1 的话,那么整个节点至少有一个子节点被选中。以此类推。focusNode
选中内容的结尾节点focusOffset
选中范围内结束位置在焦点节点下第几个子节点的位置。例如,如果是值为 0 的话,整个节点都是被选中的。如果值为 1 的话,那么整个节点至少有一个子节点被选中。以此类推。
setPosition(node, offset)
将当前所选内容折叠为单个点。文档不会被修改。如果内容是聚焦的且可编辑的,则插入符号将在此处闪烁。
js 代码解读复制代码// node 光标所处的节点, 如果指定为null,那么将删除先前的所有选中区域
// offset 光标在节点中的偏移量
// 等价于removeRanges()
getSelection().setPosition(null)
toString()
返回选择的纯文本内容。
选区对象 Range
上面我们一直在说选区(Range
),那么Range
是啥呢,下面我们来看看。
一个包含节点与文本节点的一部分的文档片段。下面这四种方式都可以获取Range
对象
document.createRange
getSection().getRangeAt()
document.caretRangeFromPoint()
Range()
属性
collapsed
表示Range
的起始位置和终止位置是否相同。即是否有选中文本。commonAncestorContainer
返回包含选区的起始和终止节点的共同父节点。
endContainer
返回包含Range
终点的节点。即getSelection().focusNode
js 代码解读复制代码getSelection().getRangeAt(0).endContainer === getSelection().focusNode // true
endOffset
返回一个表示Range
终点在endContainer
中的位置的数字。即getSelection().focusOffset
js 代码解读复制代码getSelection().getRangeAt(0).endOffset === getSelection().focusOffset // true
startContainer
返回包含Range
开始的节点。即getSelection().anchorNode
js 代码解读复制代码getSelection().getRangeAt(0).startContainer === getSelection().anchorNode // true
startOffset
返回一个数字,表示Range
在startContainer
中的起始位置。即getSelection().anchorOffset
js 代码解读复制代码getSelection().getRangeAt(0).startOffset === getSelection().anchorOffset // true
方法
Range.cloneContents()
返回一个 DocumentFragment
,它是 Range
中所有的 Node
对象的副本。
Range.cloneRange()
克隆一个Range
对象。
克隆是按值复制的,而非按引用复制,因此其中一个Range
的更改不会影响另一个。
js 代码解读复制代码getSelection().getRangeAt(0).cloneRange() === getSelection().getRangeAt(0) // false
Range.collapse()
取消选区,并聚焦到选区的尾部。
Range.insertNode(newNode)
在Range
的起始位置插入节点。并成为选取的一部分。
新节点是插入在 Range
起始位置。如果将新节点添加到一个文本节点,则该节点在插入点处被拆分,插入发生在两个文本节点之间。如果新节点是一个文档片段,则插入文档片段的子节点。
Range.deleteContents()
移除来自Document
的Range
内容。不像Range.extractContents
一样,本方法不会返回一个包含删除内容的文本片段DocumentFragment
。等同于getSelection().deleteFromDocument()
。 如果选中区域包含元素也一同删除。
Range.extractContents()
将 Range
的内容从文档树中移到 DocumentFragment
中。类似于getSelection().deleteFromDocument()
Range.getBoundingClientRect()
一个 DOMRect
对象,该对象将选中区域中的内容包围起来;即该对象是一个将范围内所有元素的边界矩形包围起来的矩形。
Range.getClientRects()
返回一个 DOMRect
对象列表,表示range
在屏幕上所占的区域。这个列表相当于汇集了范围中所有元素调用Element.getClientRects()
方法所得的结果。
Range.intersectsNode(Node)
返回一个指示给定的 Node
是否与 Range
相交的布尔值。即是否选中Node
节点(部分)内容
selectNode(referenceNode)
将 Range
设置为包含整个 Node
及其内容。Range
的起始和结束节点的父节点与 referenceNode 的父节点相同。
Range.selectNodeContents(referenceNode)
设置选区选中referenceNode
节点内容。startOffset
为 0,endOffset
则是引用节点包含的字符数或子节点个数。
Range.setEnd()
设置 Range
的结束位置。 如果结束节点类型是 Text
、Comment
或 CDATASection
之一,那么 endOffset
指的是从结束节点算起字符的偏移量。对于其他 Node
类型节点,endOffset
是指从结束结点开始算起子节点的偏移量。
如果设置的结束点在起始点之上(在文档中的位置),将会导致选区折叠,起始点和结束点都会被设置为指定的结束位置。
Range.setEndBefore(referenceNode),Range.setEndAfter(referenceNode)
Range.setEndBefore(referenceNode)
修改选区范围,将Range
的结束位置设置在另一个Node
之前Range.setEndAfter(referenceNode)
修改选区范围,将Range
的结束位置设置在另一个Node
之后
Range.setStart(startNode, startOffset)
用于设置Range
的开始位置。如果起始节点类型是 Text
、Comment
或 CDATASection
之一,那么 startOffset
指的是从起始节点算起字符的偏移量。对于其他 Node
类型节点,startOffset
是指从起始结点开始算起子节点的偏移量。
如果设置的起始位点在结束点之下(在文档中的位置),将会导致选区折叠,起始点和结束点都会被设置为指定的起始位置。
Range.setStartAfter()
修改选区范围,将Range
的起始位置设置在另一个 Node
之后(即选区内容不包括Node
中的内容,如果设置的是选区共同的节点,那么将删除选区并将光标聚焦到referenceNode
处)。如果设置的节点在选区节点后方,那么将选区删除并将光标聚焦到referenceNode
处。
Range.setStartBefore(referenceNode)
修改选区范围,将Range
的起始位置设置在另一个 Node
之前(即选区内容包括Node
中的内容)。如果设置的节点在选区节点后方,那么将选区删除并将光标聚焦到referenceNode
处。
Range.surroundContents(node)
将node节点同样的标签包裹将Range
的内容。
js 代码解读复制代码// 将内容用div元素包裹
getSelection().getRangeAt(0).surroundContents(document.createElement("div"))
toString()
获取选区中的文本。等价于window.getSelection().toString()
如何在开发中使用起来呢
- 高亮选中的文本
js 代码解读复制代码document.addEventListener("mouseup", () => {
const selection = window.getSelection();
if (selection.isCollapsed) return;
const range = selection.getRangeAt(0);
const highlight = document.createElement("span");
highlight.className = "highlight";
range.surroundContents(highlight);
selection.removeAllRanges(); // 取消选中状态
});
// CSS
.highlight { background: yellow; }
- 增强复制文本的功能
js 代码解读复制代码document.addEventListener("copy", (e) => {
const selection = window.getSelection();
const originalText = selection.toString();
const appendedText = `${originalText}\n\n—— 来自掘金`;
e.clipboardData.setData("text/plain", appendedText);
e.preventDefault(); // 阻止默认复制行为
});
- 禁止用户选择
js 代码解读复制代码// 监听选择事件,若选中禁止区域则清空选择
document.addEventListener("selectionchange", () => {
const selection = window.getSelection();
const forbiddenElement = document.querySelector(".no-select");
if (forbiddenElement?.contains(selection.anchorNode)) {
selection.removeAllRanges();
}
});
- 保留用户选中的html结构
js 代码解读复制代码function getSelectedHTML() {
const selection = window.getSelection();
if (selection.rangeCount === 0) return "";
const range = selection.getRangeAt(0);
const div = document.createElement("div");
div.appendChild(range.cloneContents());
return div.innerHTML;
}
- 在上海的忙碌一年,依旧充满憧憬(2024)
- 四年沿海城市,刚毕业,一年3家公司
- 七月仿佛又回到了那一年(2023年中总结)
- 一位初入职场前端仔的年度终结 <回顾2022,展望2023>
- 大学两年半的前端学习
往期文章
- 前端可以知道的录制浏览器标签页,没有黑魔法
- 一个关联本地页面镜像的功能,我了解到这些
- 啊,原来sessionStorage是这样的
- 如何像掘金编辑器一样粘贴图片即可上传服务器
- Nest装饰器全解析
- Nest世界中的AOP
- Nestjs如何解析http传输的数据
- 如何理解js的DOM事件系统
- 半年没看vue官网,3.5刚刚发布,趁机整理下
- 啊,你还在找一款强大的表格组件吗?
- 前端大量数据层级展示及搜索定位预览
- 如何从0开始认识m3u8(提取,解析及下载)
- 展示大量数据节点(tree),引发的一次性能排查
- ts装饰器的那点东西
- 这是你所知道的ts类型断言和类型守卫吗?
- TypeScript官网内容解读
- 经常使用ts的你,知道这些内容?
- 你有了解过原生css的scope?
- 现在比较常用的移动端调试你知道哪些?
- 众多跨标签页通信方式,你知道哪些?(二)
- 众多跨标签页通信方式,你知道哪些?
- 反调试吗?如何监听devtools的打开与关闭
- 因为原生,选择一家公司(前端如何防笔试作弊)
- 结合开发,带你熟悉package.json与tsconfig.json配置
- 如何优雅的在项目中使用echarts
- 如何优雅的做项目国际化
- 近三个月的排错,原来的憧憬消失喽
- 带你从0开始了解vue3核心(运行时)
- 带你从0开始了解vue3核心(computed, watch)
- 带你从0开始了解vue3核心(响应式)
- 3w+字的后台管理通用功能解决方案送给你
- 入职之前,狂补技术,4w字的前端技术解决方案送给你(vue3 + vite )
专栏文章
🔥如果此文对你有帮助的话,欢迎💗关注、👍点赞、⭐收藏、✍️评论, 支持一下博主~
公众号:全栈追逐者,不定期的更新内容,关注不错过哦!
评论记录:
回复评论: