首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

文本选区有啥魔力

  • 25-04-20 17:01
  • 2718
  • 11140
juejin.cn

最近在看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); }

image.png

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()

image.png

extend(node, offset)

扩展选择到新位置。

js
代码解读
复制代码
// node 焦点应该被拓展到的区域。 // offset 在node中的偏移。 window.getSelection().extend($0, 1)

image.png

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)

image.png

toString()

返回选择的纯文本内容。

选区对象 Range

上面我们一直在说选区(Range),那么Range是啥呢,下面我们来看看。

一个包含节点与文本节点的一部分的文档片段。下面这四种方式都可以获取Range对象

  • document.createRange
  • getSection().getRangeAt()
  • document.caretRangeFromPoint()
  • Range()

属性

  • collapsed表示 Range 的起始位置和终止位置是否相同。即是否有选中文本。
  • commonAncestorContainer 返回包含选区的起始和终止节点的共同父节点。

image.png

  • 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对象的副本。

image.png

Range.cloneRange()  

克隆一个Range对象。

克隆是按值复制的,而非按引用复制,因此其中一个Range的更改不会影响另一个。

js
代码解读
复制代码
getSelection().getRangeAt(0).cloneRange() === getSelection().getRangeAt(0) // false

Range.collapse()  

取消选区,并聚焦到选区的尾部。

image.png

Range.insertNode(newNode)

在Range的起始位置插入节点。并成为选取的一部分。

新节点是插入在 Range 起始位置。如果将新节点添加到一个文本节点,则该节点在插入点处被拆分,插入发生在两个文本节点之间。如果新节点是一个文档片段,则插入文档片段的子节点。

image.png

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处。

image.png

image.png

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 )

专栏文章

  • 重学vue及其生态
  • 前端面试
  • 前端工程化
  • amis 低代码实战
  • 协议与安全
  • 重学react
  • 重学nodejs
  • 工作总结

🔥如果此文对你有帮助的话,欢迎💗关注、👍点赞、⭐收藏、✍️评论,    支持一下博主~

公众号:全栈追逐者,不定期的更新内容,关注不错过哦!

注:本文转载自juejin.cn的Spirited_Away的文章"https://juejin.cn/post/7494546904757567522"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2491) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

104
前端
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top