You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 18:15:00