功能清单
我写了个demo实现“@提及”功能,已完成的交互有:
- 点击“@用户”按钮会在光标处插入蓝色的[@用户0]
a. 若光标在[@用户0]内部,点击“@用户”按钮则自动将插入位置挪到[@用户0]之后,避免嵌套。 - 点击“@用户”按钮插入的[@用户0]是蓝色的,在它前后输入内容默认是黑色。
- 光标在[@用户0]右侧,按下删除键,会将它整体删除。如果选择文字范围包括[@用户0],也会将它整体删除。
- 在[@用户0]里键入、粘贴文字或选中部分文字后修改,都会被判定为“@被改写”,会降级成普通黑色文本。
- 复制蓝色[@用户0]后再粘贴,会作为黑色文本展示,而不是@。
没办法上传视频,附上一张图片:
也可以直接下载代码,本地体验下交互:https://developers.weixin.qq.com/s/eSz42MmP8n5e
核心数据结构
用零宽字符作为“提及”的隐形边界
mentionSentinel: '\u200B', // 零宽字符作为哨兵
// "@用户X"
const rawMention = '@用户' + mentionId
// [哨兵] + "@用户X" + [哨兵] + " "
const mentionText = mentionSentinel + rawMention + mentionSentinel + ' '
维护快照
lastSnapshotText: '', // 最近一次快照,包含哨兵字符
lastMentions: [], // 最近一次快照中解析出的所有提及区间
mentionWhitelist: [], // 记录当前允许作为提及存在的原始文案(例如 @用户0),为了解决各种交互下残留的蓝色样式。
互斥锁
mentionDeletionLock: false, // 提及删除期间的互斥锁
mentionRewriteLock: false, // 粘贴去哨兵时的互斥锁
这两个互斥锁作用在 onEditorInput 方法,因为用户输入、调用 editorCtx.deleteText / insertText 都会触发 onEditorInput,加互斥锁是为了区分「用户打字」还是「程序修改」。
思路解析
我将通过以两个交互点简单说下整体的实现思路。
