如何修复 Android Chrome 上的 inline contenteditable 中的光标跳转问题?
How to fix cursor jumping in inline contenteditable on Android Chrome?
我遇到了一个奇怪的问题:
在 contenteditable
<span>
上,在 html 中有预定义的内容,当您开始输入新词时,文本光标会跳回某个点。跳转的位置在原内容的末尾
示例:
<span contenteditable>foo</span>
这发生在 Android Chrome 91.0.4472.120,Android 11,使用 Gboard 10.6.02.371892758-release-arm64-v8a。
我还在桌面 Chrome 和 IOS Safari 上进行了测试。那里无法重现问题,只有Andriod Chrome.
对于 <p>
或 <div>
等块元素不会发生这种情况,但如果我设置 display:inline
说,<p>
使用 css, 问题与跨度相同。
即使元素最初不包含文本(例如 <span contenteditable></span>
),也不会发生这种情况,即使用户后来编辑它以包含文本也是如此。
关于为什么会发生这种情况的任何想法?这似乎是 Chrome/Android 的某种错误。有 workaround/fix 吗?
注意:我需要使用 contenteditable 和 inline,因为我希望元素在不占用整行的情况下换行,所以 input 或 textarea 不是一个选项。
这是我找到的解决方法。
如果在元素为 selected/focused 时使用 Range.insertNode()
向空元素添加文本,则不会触发此问题。
因此,我们可以清除内容,select元素,然后在元素获得焦点时使用此方法重新插入原始内容,以防止出现问题。
const onFocus = (e) => {
const selection = window.getSelection();
const selectionRange = new Range();
const originalContent = e.target.textContent;
// Clear the content and select in the empty element
e.target.textContent = '';
selectionRange.selectNodeContents(e.target);
selection.removeAllRanges();
selection.addRange(selectionRange);
// Re-insert the content and set the cursor at the end
const textNode = document.createTextNode(originalContent);
selectionRange.insertNode(textNode);
selectionRange.selectNodeContents(textNode);
selectionRange.collapse(false);
}
const element = document.getElementById('element');
element.addEventListener('focus', onFocus, {once : true});
<span id="element" contenteditable>foo</span>
副作用:我无法在重新插入后将插入符号重置为其初始位置,因此我将光标置于内容的末尾。这意味着点击文本中间会转到末尾,但用户始终可以在元素获得焦点后再次点击。
我遇到了一个奇怪的问题:
在 contenteditable
<span>
上,在 html 中有预定义的内容,当您开始输入新词时,文本光标会跳回某个点。跳转的位置在原内容的末尾
示例:
<span contenteditable>foo</span>
这发生在 Android Chrome 91.0.4472.120,Android 11,使用 Gboard 10.6.02.371892758-release-arm64-v8a。 我还在桌面 Chrome 和 IOS Safari 上进行了测试。那里无法重现问题,只有Andriod Chrome.
对于 <p>
或 <div>
等块元素不会发生这种情况,但如果我设置 display:inline
说,<p>
使用 css, 问题与跨度相同。
即使元素最初不包含文本(例如 <span contenteditable></span>
),也不会发生这种情况,即使用户后来编辑它以包含文本也是如此。
关于为什么会发生这种情况的任何想法?这似乎是 Chrome/Android 的某种错误。有 workaround/fix 吗?
注意:我需要使用 contenteditable 和 inline,因为我希望元素在不占用整行的情况下换行,所以 input 或 textarea 不是一个选项。
这是我找到的解决方法。
如果在元素为 selected/focused 时使用 Range.insertNode()
向空元素添加文本,则不会触发此问题。
因此,我们可以清除内容,select元素,然后在元素获得焦点时使用此方法重新插入原始内容,以防止出现问题。
const onFocus = (e) => {
const selection = window.getSelection();
const selectionRange = new Range();
const originalContent = e.target.textContent;
// Clear the content and select in the empty element
e.target.textContent = '';
selectionRange.selectNodeContents(e.target);
selection.removeAllRanges();
selection.addRange(selectionRange);
// Re-insert the content and set the cursor at the end
const textNode = document.createTextNode(originalContent);
selectionRange.insertNode(textNode);
selectionRange.selectNodeContents(textNode);
selectionRange.collapse(false);
}
const element = document.getElementById('element');
element.addEventListener('focus', onFocus, {once : true});
<span id="element" contenteditable>foo</span>
副作用:我无法在重新插入后将插入符号重置为其初始位置,因此我将光标置于内容的末尾。这意味着点击文本中间会转到末尾,但用户始终可以在元素获得焦点后再次点击。