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

相关推荐
2601_9623824326 分钟前
剑指大前端全栈工程师(全2册)主要情节
javascript·实战案例·全栈工程师·剑指大前端·html5+css3
泯泷1 小时前
手搓JSVM第 12 篇:完整最小 JSVM 实现与源码设计复盘
前端·javascript·前端框架
默_笙1 小时前
🍔 给 AI 发一张结构化表格(下):从"自由发挥"到"按格填空"的输出驯服指南
前端·javascript
泯泷1 小时前
手搓JSVM第 11 篇:打包、模块与 CLI:把 VM 产物变成可运行文件
前端·javascript·前端框架
泯泷1 小时前
手搓JSVM第 10 篇:对象、数组与属性访问
前端·javascript·前端框架
泯泷2 小时前
手搓JSVM第 9 篇:闭包:函数如何记住外部变量
前端·javascript·前端框架
晴天162 小时前
前端 SSR、BFF 原理介绍
前端·javascript·网络·html
全栈技术负责人3 小时前
AI 效能工具建设:Agent 可观测性技能技术方案与实践
前端·ai·ai编程
梦想平凡3 小时前
百游棋牌源代码开发搭建教程(一):全端工程结构、开发环境配置与首次启动验证
前端·javascript·源代码管理
妙码生花3 小时前
两个月 59 篇 AI 开发日志 + Golang 商业级实战项目收工后,得来的 AI 使用心法-上
前端·后端·gin