bounty将在3天后过期。回答此问题可获得+500声望奖励。rtom希望引起更多关注此问题。
我正在处理一个contentEditable span
,我想把一个position: absolute
元素放在光标所在的同一行上。当文本被换行时,问题就发生了,因为它不合适-换行的第一个和最后一个位置有奇怪的行为。
对于这两个,当我在第二行的第一个位置时,getBoundingClientRect()
的y
偏移量等于第一行的偏移量,但是如果我在第二行上再移动一个位置,y offset
就正确地匹配了第二行。
在下面的代码片段中,Firefox显示了这种行为。对于Chrome,它似乎工作得很好,尽管在我的完整实现中,它也有不精确的行为,但我能够解决Chrome的问题。然而,对于Firefox,第一行的最后一个位置的offset
等于第一行,第二行的第一个位置的offset
等于第一行,之后它工作得很好。
在示例中,转到第一行的最后一个位置,注意控制台中的CURRENT_TOP
值为16
。如果向右移动一个位置,光标已经在下一行,它仍然显示16
。如果再向右移动一个位置,它将显示36
const textEl = document.getElementById("myText")
textEl.addEventListener("keyup", (event) => {
const domSelection = window.getSelection();
if (domSelection && domSelection.isCollapsed && domSelection.anchorNode) {
let offsetNewLine = 0;
const domRange = domSelection.getRangeAt(0);
const rect = domRange.getBoundingClientRect();
const rects = domRange.getClientRects();
const newRange = document.createRange();
const newRangeNextOffset = domSelection.anchorNode.textContent.length < domSelection.anchorOffset + 1 ? domSelection.anchorOffset : domSelection.anchorOffset + 1
newRange.setStart(domSelection.anchorNode, newRangeNextOffset);
newRange.setEnd(domSelection.anchorNode, newRangeNextOffset);
const nextCharacterRect = newRange.getBoundingClientRect();
console.log(`CURRENT_TOP: ${rect.y}, NEXT_CHAR_TOP: ${nextCharacterRect.y}`);
}
})
.text-container {
width: 500px;
display: inline-block;
border: 1px solid black;
line-height: 20px;
padding: 5px;
}
<span id="myText" class="text-container" contentEditable="true">Go on the last position in the first row and come it to first position in the second row</span>
2条答案
按热度按时间avwztpqn1#
诊断
这种奇怪的行为发生的原因是,Chrome和Firefox似乎对待换行的方式不同。在Chrome和Firefox中执行以下代码片段。唯一的区别是,我添加了
字符串
到控制台输出。我们将在下面讨论结果。
x
的字符串
浏览器在不同的位置换行,但这不是重点。先看看Chrome中的输出。注意,caret直接跳到下一行,实际存在的空格已经 * 转换 * 为换行符(NL),并且似乎是经典的回车加换行符(CR+LF)形式。因此,NL Chrome看到光标后,就像人眼一样,已经在2号线了。
| 第1行的最后一个非空格|换行|第2行的第一个非空格|
| --|--|--|
| 偏移量61处的“t”|偏移62处的NL|偏移量63处的“p”|
x1c 0d1x的数据
现在Firefox。插入符号跟随空格,然后**跳到下一行。空格(SP)被保留。但是 * 插入的 * 换行符 * 没有 * 被包括在偏移计算中。此外,它仍然被视为第1行的一部分,即人眼看到的光标在第2行,但Firefox在第1行。无论如何。
所以Firefox在第1行的末尾迭代了 * 两次 *(SP然后NL),但是只增加了 * 一次 * 偏移量(SP和NL一起),而且还没有真正移动到第2行。所有这些都使得这里的事情变得如此混乱。
| 第1行的最后一个非空格|换行|第2行的第一个非空格|
| --|--|--|
| 偏移量73处的“n”|SP * 和 * NL,偏移量均为74|偏移量为75的“t”|
的
方法
我目前能想到的唯一方法是检测浏览器并引入Firefox特定的解决方案,因此要检查Firefox,例如,
型
经过测试,仍然适用于Firefox 111。
9bfwbjaz2#
正如@Krokomot所解释的那样,Firefox有一种古怪的方式来处理换行。
事实上,前一行的末尾 * 和当前行的开头 *(显示光标/插入符号)将返回相同的字符索引/位置(或
anchorOffset
值)。解决方法是保存全局变量中最后一个字符索引和最后一个顶部
y
值。如果当前字符位置和前一个top y等于前一个
anchorOffset + 1
)计算y位置-在这种情况下,在换行符之后。上面的示例还根据鼠标输入检查新插入符号的位置。
然而,当使用向上/向下箭头键时,这种方法仍然失败。