可编辑 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 详解

相关推荐
WayneX1 分钟前
Vue 3 + TypeScript + Vite 组件库搭建,自助式生成相应组件文档
前端·javascript·vue.js
SunnyJingJing2 分钟前
2026 css自适应实现布局方式
前端
贾铭2 分钟前
如何实现一个网页版的剪映(四)使用插件化思维创建pixi绘制画布(转场/滤镜)
前端·javascript
kgduu6 分钟前
js之xml处理
xml·前端·javascript
凌览11 分钟前
尤雨溪新公司官宣!Vite+ 正式开源,前端圈要变天了?
前端·javascript·后端
Highcharts.js16 分钟前
在 Highcharts 中实现 Marimekko可变宽度图|示例教程
javascript·highcharts·图表开发·可视化图表库·可变宽图
We་ct19 分钟前
LeetCode 22. 括号生成:DFS回溯解法详解
前端·数据结构·算法·leetcode·typescript·深度优先·回溯
Mr_Mao30 分钟前
什么?我居然在 React 用 Pinia?
前端
老虎06271 小时前
ECharts 基础与折线图
前端·echarts
小雨青年1 小时前
鸿蒙 HarmonyOS 6 | 混合开发 (01) Web 组件内核——ArkWeb 加载机制与 Cookie 管理
前端·华为·harmonyos