contenteditable div使用TributeJS实现@提及功能时退格无法删除内部节点问题
解决方案
问题根因
Chrome在处理相邻的contenteditable="false"元素、且元素之间无空白文本节点、跨多行排布时,会出现光标定位异常:退格到两个提及元素临界位置时,浏览器误判当前没有可删除的内容,终止了删除动作。
修复思路
通过监听退格键的keydown事件手动处理删除逻辑,跳过浏览器默认的异常判断,直接操作DOM删除目标提及节点。
可直接复用的实现代码
const editableBox = document.querySelector('#你的contenteditable容器ID'); editableBox.addEventListener('keydown', function(e) { // 只拦截退格键 if (e.keyCode !== 8) return; const selection = window.getSelection(); // 非单光标选中状态直接走默认逻辑 if (selection.rangeCount !== 1 || !selection.isCollapsed) return; const range = selection.getRangeAt(0); // 光标已经在容器最开头不需要处理 if (range.startOffset === 0 && range.startContainer === editableBox) { return; } // 定位光标前的相邻节点 let targetMentionNode; if (range.startOffset === 0) { targetMentionNode = range.startContainer.previousSibling; } else if (range.startContainer.nodeType === Node.TEXT_NODE && range.startOffset === 1) { // 兼容零宽空格占位的场景 if (range.startContainer.textContent === '\u200B') { targetMentionNode = range.startContainer.previousSibling; } } // 判定前一个节点为不可编辑的提及标签时手动删除 if (targetMentionNode && targetMentionNode.nodeType === Node.ELEMENT_NODE && targetMentionNode.classList.contains('mention') && targetMentionNode.getAttribute('contenteditable') === 'false') { targetMentionNode.remove(); e.preventDefault(); // 重新定位光标到容器末尾 const newRange = document.createRange(); newRange.selectNodeContents(editableBox); newRange.collapse(false); selection.removeAllRanges(); selection.addRange(newRange); } });
额外优化建议
可以在TributeJS生成提及标签的回调逻辑里,给每个提及标签后面自动插入一个零宽空格\u200B,避免多个提及标签直接相邻触发Chrome的原生光标bug,能从根源减少这类异常场景出现的概率。
内容的提问来源于stack exchange,提问作者Zer0Skill
相关产品推荐
相关产品推荐

