这个答案可能对你来说晚了几年,但我遇到了类似的问题,并想在这里记录下来,因为它是谷歌搜索的第一个结果。
再次强调,问题是你想从用户选择中捕获 Range 对象,并用一个有样式的 div 包围它,就像这样:
function highlightSelection() {
var userSelection = window.getSelection().getRangeAt(0);
highlightRange(userSelection);
}
function highlightRange(range) {
var newNode = document.createElement("div");
newNode.setAttribute(
"style",
"background-color: yellow; display: inline;"
);
range.surroundContents(newNode);
}
但正如原始父级所述,这是不安全的。如果选择不跨越元素边界,它将起作用;但如果用户选择创建的范围是一个不安全范围,跨越HTML标签的边界,它将抛出DOM错误。
解决方案是生成一个较小的 Range 对象数组,这些对象都没有单独跨越元素边界,但共同覆盖了用户选择的范围。可以像上面那样突出显示每个安全范围。
function getSafeRanges(dangerous) {
var a = dangerous.commonAncestorContainer;
var s = new Array(0), rs = new Array(0);
if (dangerous.startContainer != a)
for(var i = dangerous.startContainer; i != a; i = i.parentNode)
s.push(i)
;
if (0 < s.length) for(var i = 0; i < s.length; i++) {
var xs = document.createRange();
if (i) {
xs.setStartAfter(s[i-1]);
xs.setEndAfter(s[i].lastChild);
}
else {
xs.setStart(s[i], dangerous.startOffset);
xs.setEndAfter(
(s[i].nodeType == Node.TEXT_NODE)
? s[i] : s[i].lastChild
);
}
rs.push(xs);
}
var e = new Array(0), re = new Array(0);
if (dangerous.endContainer != a)
for(var i = dangerous.endContainer; i != a; i = i.parentNode)
e.push(i)
;
if (0 < e.length) for(var i = 0; i < e.length; i++) {
var xe = document.createRange();
if (i) {
xe.setStartBefore(e[i].firstChild);
xe.setEndBefore(e[i-1]);
}
else {
xe.setStartBefore(
(e[i].nodeType == Node.TEXT_NODE)
? e[i] : e[i].firstChild
);
xe.setEnd(e[i], dangerous.endOffset);
}
re.unshift(xe);
}
if ((0 < s.length) && (0 < e.length)) {
var xm = document.createRange();
xm.setStartAfter(s[s.length - 1]);
xm.setEndBefore(e[e.length - 1]);
}
else {
return [dangerous];
}
rs.push(xm);
response = rs.concat(re);
return response;
}
然后,可以通过以下修改的代码来(似乎)突出显示用户选择:
function highlightSelection() {
var userSelection = window.getSelection().getRangeAt(0);
var safeRanges = getSafeRanges(userSelection);
for (var i = 0; i < safeRanges.length; i++) {
highlightRange(safeRanges[i]);
}
}
请注意,您可能需要一些更高级的CSS来使许多不同的元素在用户眼中看起来很好。我希望最终这能对其他在互联网上疲惫的灵魂有所帮助!
工作示例
document.addEventListener('mouseup', highlightSelection);
function highlightSelection() {
var userSelection = window.getSelection().getRangeAt(0);
var safeRanges = getSafeRanges(userSelection);
for (var i = 0; i < safeRanges.length; i++) {
highlightRange(safeRanges[i]);
}
}
function highlightRange(range) {
var newNode = document.createElement("div");
newNode.setAttribute(
"style",
"background-color: yellow; display: inline;"
);
range.surroundContents(newNode);
}
function getSafeRanges(dangerous) {
var a = dangerous.commonAncestorContainer;
var s = new Array(0), rs = new Array(0);
if (dangerous.startContainer != a) {
for (var i = dangerous.startContainer; i != a; i = i.parentNode) {
s.push(i);
}
}
if (s.length > 0) {
for (var i = 0; i < s.length; i++) {
var xs = document.createRange();
if (i) {
xs.setStartAfter(s[i - 1]);
xs.setEndAfter(s[i].lastChild);
} else {
xs.setStart(s[i], dangerous.startOffset);
xs.setEndAfter((s[i].nodeType == Node.TEXT_NODE) ? s[i] : s[i].lastChild);
}
rs.push(xs);
}
}
var e = new Array(0), re = new Array(0);
if (dangerous.endContainer != a) {
for (var i = dangerous.endContainer; i != a; i = i.parentNode) {
e.push(i);
}
}
if (e.length > 0) {
for (var i = 0; i < e.length; i++) {
var xe = document.createRange();
if (i) {
xe.setStartBefore(e[i].firstChild);
xe.setEndBefore(e[i - 1]);
} else {
xe.setStartBefore((e[i].nodeType == Node.TEXT_NODE) ? e[i] : e[i].firstChild);
xe.setEnd(e[i], dangerous.endOffset);
}
re.unshift(xe);
}
}
if ((s.length > 0) && (e.length > 0)) {
var xm = document.createRange();
xm.setStartAfter(s[s.length - 1]);
xm.setEndBefore(e[e.length - 1]);
} else {
return [dangerous];
}
rs.push(xm);
response = rs.concat(re);
return response;
}
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?</p>