动态更改 div 的可满足属性时,文本突出显示的奇怪双击行为
Weird double click behavior with text highlighting, when dynamically changing the contentedible attribute of a div
要求:
- 我们需要一个可编辑的 div,只有在用户点击它后才变得可编辑
- 当焦点从 div
移开时,div 恢复为只读状态
问题:
- 我可以毫无问题地实现这两个要求,但是我得到了不理想的文本突出显示行为,即双击时
- 我们希望在 div 不可编辑时单击一次会使 div 变为可编辑。在此之后单击应在 div 中设置 selection。但是,如果这两次点击发生得太快,则第二次点击将被视为双击 - 突出显示整个单词,而应该只进行 selection。我不知道如何纠正这种行为。
我尝试过的:
- 简单地使用 css,用户 -select=none 不起作用
- 也许需要防止默认的 mousedown 事件,并在 div 上手动调用 .focus(),但这种方法很难将插入符号放在正确的位置
演示代码:
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));
您可以通过添加双击事件侦听器来删除该文本选择。在那个双击侦听器上,我们可以删除文本选择。
editor.addEventListener('dblclick', e => {
const selection = window.getSelection();
const range = document.createRange();
range.selectNodeContents(editor);
selection.removeAllRanges();
})
参见this代码
问题本质上是在浏览器错误地假设点击次数高于应有的情况下发生的。我通过保留前一个 range
的存储并在需要时用前一个替换当前范围来解决它。
要求:
- 我们需要一个可编辑的 div,只有在用户点击它后才变得可编辑
- 当焦点从 div 移开时,div 恢复为只读状态
问题:
- 我可以毫无问题地实现这两个要求,但是我得到了不理想的文本突出显示行为,即双击时
- 我们希望在 div 不可编辑时单击一次会使 div 变为可编辑。在此之后单击应在 div 中设置 selection。但是,如果这两次点击发生得太快,则第二次点击将被视为双击 - 突出显示整个单词,而应该只进行 selection。我不知道如何纠正这种行为。
我尝试过的:
- 简单地使用 css,用户 -select=none 不起作用
- 也许需要防止默认的 mousedown 事件,并在 div 上手动调用 .focus(),但这种方法很难将插入符号放在正确的位置
演示代码:
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));
您可以通过添加双击事件侦听器来删除该文本选择。在那个双击侦听器上,我们可以删除文本选择。
editor.addEventListener('dblclick', e => {
const selection = window.getSelection();
const range = document.createRange();
range.selectNodeContents(editor);
selection.removeAllRanges();
})
参见this代码
问题本质上是在浏览器错误地假设点击次数高于应有的情况下发生的。我通过保留前一个 range
的存储并在需要时用前一个替换当前范围来解决它。