可编辑 div,名称染色交互方案

需求描述

用户在一段文本输入过程中,如果遇到系统内存在的姓名就用蓝色标识出来,也可以在光标处通过点击姓名的方式把姓名加进去。

交互细节,拆分

  • 中括号文本内容,匹配到姓名,颜色标蓝色,不符合条件则不标记颜色
  • 在鼠标焦点位置,可以粘贴文本
  • 在鼠标焦点位置,可以点击姓名插入
  • 复制粘贴姓名后,蓝色样式还在

首先了解下 window.getSelection() 是什么 ?

它返回一个 Selection 对象,表示用户选择的文本范围或光标的当前位置。

如果一个用户光标在这里:

此时可编辑 div 内部有四个子节点

此时获取 window.getSelection() 返回的结果是:

可以看到现在焦点所在的位置是第二个文本节点内(展开 anchorNode),#text 类型,位置在第二个文本节点的第二个元素后面,因为 anchorOffset: 2

方案步骤描述(onInput)

初期方案是,维护各自的块内容,比如如果用户操作的是第二个 text 内容块,那么就根据当前块的内容和位移,进行格式化当前文本,这样焦点不会有问题。但是如果用户跨 childNode 如果形成了新的内容,复制或者粘贴半个块,就会比较难处理了,需要控制的交互边界比较多,所以这里采用了现在的方案。

  1. 监听 div 的 onInput 事件,每次变动后获取最新的文本 e.target.innerText
  2. 记录此时光标在纯文本的位置,比如上面的例子,记录的位置应该是 6
  3. 此时将文本格式化,对的名称用 font 包裹
python 复制代码
# before
 [张三]去了一趟理塘,[李四]去了一趟丽江。
 
 # after, 用 font 包裹
 <font color="#1E90FF">[张三]</font>去了一趟理塘,<font color="#1E90FF">[李四]</font>去了一趟丽江。
  1. 将格式化后的内容重新塞到 div 的 innerHTML 中,dom 重绘,获取新的 childNodes;
  2. 根据记录的焦点位置,对应到新的 nodes 上面,并且存为新的焦点,设置到 selection 上
js 复制代码
// 将光标塞到计算出的新的位置
const selection = window.getSelection();
selection.removeAllRanges(); // 将现在的 selection 选区中光标的选择范围全部清除

const range = document.createRange(); // 生成一个光标选择范围
range.selectNodeContents(divRef.current); // 将选区设置到当前的 div
range.collapse(true); // 折叠选取,光标处于开始位置
range.setEnd(newAnchorNode, newAnchorOffset); // 设置光标结束点,到选区中的某个 node 的 offset 位置
range.setStart(newAnchorNode, newAnchorOffset); // 设置开始点

selection.addRange(range); // 将创建的新的光标 塞入当前的 selection 中
  1. 此时焦点正确,内容也格式化完成。

点击插入名称的实现

  1. 在 div onBlur 的时候记录下当时的焦点信息,位置,比如 6
  2. 点击时候,获取到焦点信息,没有就取末尾
  3. 将当前 div 内部的文本按照焦点位置分割,分为开头和结尾
  4. 将姓名插入形成新的文本,比如在张三后面插入李四,新文本是 [张三][李四]去了一趟理塘,[李四]去了一趟丽江。
  5. 重新格式化上述文本,之后塞到 div 的 innerHTML 里面,失焦处理

代码实现

demo 代码:github

参考

可编辑 div ,window.getSelection() api 详解

相关推荐
灵犀学长6 分钟前
解锁HTML5页面生命周期API:前端开发的新视角
前端·html·html5
江号软件分享14 分钟前
轻松解决Office版本冲突问题:卸载是关键
前端
致博软件F2BPM21 分钟前
Element Plus和Ant Design Vue深度对比分析与选型指南
前端·javascript·vue.js
慧一居士1 小时前
flex 布局完整功能介绍和示例演示
前端
DoraBigHead1 小时前
小哆啦解题记——两数失踪事件
前端·算法·面试
一斤代码7 小时前
vue3 下载图片(标签内容可转图)
前端·javascript·vue
中微子7 小时前
React Router 源码深度剖析解决面试中的深层次问题
前端·react.js
光影少年7 小时前
从前端转go开发的学习路线
前端·学习·golang
中微子7 小时前
React Router 面试指南:从基础到实战
前端·react.js·前端框架
3Katrina7 小时前
深入理解 useLayoutEffect:解决 UI "闪烁"问题的利器
前端·javascript·面试