使用javascript的内容可编辑div中多行选择的字符位置



请看一下这个小提琴:

https://jsfiddle.net/darrengates/jwx41Lkz/

在本例中,我有一个包含3行的可编辑div。我正在尝试获取所选内容的开始字符位置和结束字符位置。

这似乎只适用于第一行。如果我高亮显示了1行以上,则值不正确(请参阅注释以获得解释(。

当一个选择跨越多行时,如何获得它的开始和结束字符位置?(即,从整个div的第一个字母开始的字符位置,因此例如"第二行"中的"s"大约是字符位置11(。

以下是我到目前为止所拥有的(可在小提琴中运行(:

<div id="test" contenteditable="true" class="selecttest">
first line<br />
second line<br />
third line
</div>
.selecttest {
width: 400px;
height: 200px;
border: 1px solid black;
padding: 5px;
font-size: 20px;
}
function getSelection() {
const sel = document.getSelection() || window.getSelection();
// note: if I highlight the 2nd and 3rd lines
// start and end values are 1, 11
// they should be about 11 and 22 (or so)
// on account of the existence of the first line

let start = sel.baseOffset
let end = sel.extentOffset

// if selected from right to left, reverse...
if ( start > end ) {
const temp = start;
start = end;
end = temp;
}

console.log('start, end', start, end)
}
$("#test").on('mouseup', function() {
getSelection();
})

似乎有很多S.O.的帖子与获取所选文本有关,但当选择多行时,与获得所选字符位置有关的答案都会失败。

由于要测量范围中的位置,因此应该使用范围对象而不是选择对象。

关于这种代码笔的建议>https://codepen.io/aSH-uncover/pen/ExEdXwy

主要技巧是解决范围是否在同一容器内的两种情况:(

function getSelection() {
const sel = document.getSelection() || window.getSelection();
const range = sel.getRangeAt(0)

let rangeContainer = range.commonAncestorContainer
let same = false
if (rangeContainer === range.startContainer) {
same = true
rangeContainer = range.startContainer.parentElement
}

let start = -1
let end = -1

const list = rangeContainer.childNodes
let offset = 0
for (let i = 0 ; i < list.length ; i++) {
const current = list[i]
if (current === range.startContainer) {
start = offset + range.startOffset
if (same) {
end = offset + range.endOffset
break
}
} else if (current === range.endContainer) {
end = offset + range.endOffset
break
}
if (current.nodeName === '#text') {
offset += current.length
}
}

console.log('start, end', start, end)
}

编辑:如果你想支持更复杂的文本(比如带有跨度的div(,你必须改进这个函数,并包含一些递归的东西:(

最新更新