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

Chrome中contenteditable容器内不可编辑元素的Backspace异常问题

Chrome中contenteditable内不可编辑元素批量删除问题解决

问题场景

在Chrome浏览器中,当给contenteditable="true"的div添加多个contenteditable="false"且user-select: none的span元素时,会出现异常行为:

  • 多个span处于同一行时,将光标移至行尾按下Backspace会删除div内全部内容;
  • 若将span分至不同行,Backspace仅删除最后一个不可编辑元素,符合预期。

手动给span换行可临时解决问题,但由于需动态添加不可编辑元素,该方法不适用,需针对Chrome适配解决。

代码示例

简化复现代码

<div contenteditable="true">
  some random text
  <span contenteditable="false" style="user-select: none">1</span><span contenteditable="false" style="user-select: none">2</span>
</div>

动态添加元素完整示例

HTML

<!DOCTYPE html>
<html>
<head>
  <title>Parcel Sandbox</title>
  <meta charset="UTF-8" />
</head>
<body>
  <div id="app">
    <div spellcheck="false" contenteditable="true" class="input" id="snafu">
      <span>添加至少2个不可编辑标签后,把光标移到行尾按Backspace测试</span>
    </div>
    <button id="button" class="button">添加标签</button>
  </div>
  <script src="src/index.js"></script>
</body>
</html>

CSS

body {
  font-family: sans-serif;
}

.input {
  color: green;
  box-shadow: 2px 2px 10px mediumaquamarine;
  padding: 8px;
  border-radius: 8px;
  margin-bottom: 24px;
}

.xml-tag {
  display: inline-flex;
  justify-content: center;
  align-items: center;
  width: 16px;
  height: 16px;
  margin-inline: 2px;
  user-select: none;
  border-radius: 50%;
  background: lime;
  font-size: 10px;
  white-space: pre;
}

.button {
  background: transparent;
  box-shadow: 3px 3px 5px limegreen;
  border: none;
  border-radius: 8px;
  padding: 8px;
}

.button:hover {
  transform: scale(1.1);
  cursor: pointer;
}

JavaScript

const input = document.getElementById("snafu");
const button = document.getElementById("button");

const onClick = () => {
  const tag = document.createElement("span");
  tag.setAttribute("contenteditable", false);
  tag.classList.add("xml-tag");
  tag.innerHTML = "t";
  input.append(tag);
};

button.addEventListener("click", onClick);

解决方案

方案一:插入零宽空格分隔节点

在每个动态添加的span后插入一个零宽空格(\u200B),视觉上无影响,但可让Chrome将每个不可编辑span识别为独立节点,避免批量删除。修改添加元素的代码:

const onClick = () => {
  const tag = document.createElement("span");
  tag.setAttribute("contenteditable", false);
  tag.classList.add("xml-tag");
  tag.innerHTML = "t";
  input.append(tag);
  // 插入零宽空格用于分隔节点
  input.append(document.createTextNode("\u200B"));
};

方案二:手动监听Backspace事件控制删除行为

通过监听keydown事件,判断光标位置后手动删除最后一个不可编辑元素,完全控制删除逻辑:

input.addEventListener('keydown', (e) => {
  if (e.key !== 'Backspace') return;

  const selection = window.getSelection();
  const range = selection.getRangeAt(0);

  // 确认光标处于内容末尾
  const isAtEnd = range.startContainer === input && range.startOffset === input.childNodes.length;
  if (!isAtEnd) return;

  // 从后往前查找第一个不可编辑的span
  for (let i = input.childNodes.length - 1; i >= 0; i--) {
    const node = input.childNodes[i];
    if (node.tagName === 'SPAN' && node.contentEditable === 'false') {
      e.preventDefault(); // 阻止浏览器默认的异常删除行为
      input.removeChild(node);
      // 若使用了方案一,同时删除前面的零宽空格
      if (i > 0 && input.childNodes[i-1].nodeType === Node.TEXT_NODE && input.childNodes[i-1].textContent === '\u200B') {
        input.removeChild(input.childNodes[i-1]);
      }
      break;
    }
  }
});

效果说明

  • 方案一实现简单,零宽空格不会影响页面布局,能快速解决Chrome的批量删除问题;
  • 方案二更灵活,适合需要自定义删除逻辑的复杂场景,完全规避浏览器的异常行为。

内容的提问来源于stack exchange,提问作者Victor Zhuravlev

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 04:35:56