动态更改 div 的可满足属性时,文本突出显示的奇怪双击行为

Weird double click behavior with text highlighting, when dynamically changing the contentedible attribute of a div

要求:

  1. 我们需要一个可编辑的 div,只有在用户点击它后才变得可编辑
  2. 当焦点从 div
  3. 移开时,div 恢复为只读状态

问题:

我尝试过的:

演示代码:

HTML 只是一个简单的 contenteditable div,contenteditable 最初为 false(只读)。我的真实代码是用slatejs完成的,但是这个问题可以在这里演示

<div contenteditable="false">
  initial text
</div>

一些样式可以更好地区分只读状态和可编辑状态

[contenteditable] {
  border: 6px solid #333;
  border-radius: 2px;
  padding: 2px;
  outline: none;
  min-height: 1em;
}

[contenteditable="false"] {
  border-color: rgb(238, 192, 192);
  color: #aaa;
  user-select: none;
}

[contenteditable="true"] {
  border-color: green;
  color: black;
}

实现上述 2 个要求的基本 js:

const editor = document.querySelector('[contenteditable]');

let hasFocus = false;
function setHasFocus(newFocus) {
    editor.setAttribute('contenteditable', newFocus);
  hasFocus = newFocus;
}

editor.addEventListener('mousedown', e => {
    e.stopPropagation();
    if (!hasFocus) {
    e.preventDefault();
    setHasFocus(true);
  }
})

document.addEventListener('mousedown', () => setHasFocus(false));

在沙盒中: https://jsfiddle.net/bv93sLn6/30/

您可以通过添加双击事件侦听器来删除该文本选择。在那个双击侦听器上,我们可以删除文本选择。

editor.addEventListener('dblclick', e => {
    const selection = window.getSelection();
    const range = document.createRange();
    range.selectNodeContents(editor);
    selection.removeAllRanges();
})

参见this代码

问题本质上是在浏览器错误地假设点击次数高于应有的情况下发生的。我通过保留前一个 range 的存储并在需要时用前一个替换当前范围来解决它。

沙盒:https://jsfiddle.net/2gvxrf3y/56/