在测试或创建此类解决方案时最有用的答案时,赏金将在最新版本的Firefox,Chrome和Internet Explorer中获得最快的解决方案,如jsPerf所示。 由我自行决定。 Mwahahaha!
我将主要对解决方案感到满意,该解决方案采用所有偏移和未经处理的<span>
并添加突出显示,因此parent.textContent = parent.textContent
然后在更新的偏移列表上运行解决方案将重新突出显示,但这具有不利的时间复杂性,因此不是首选。
我有一个只包含文字的元素,我想突出显示。我还有一个[startline, startcol, endline, endcol]
数组,知道.textContent
中每行的长度,我可以归一化为[startoffset, endoffset]
。如何在每对偏移之间突出显示?
这个问题比看起来更难,因为:
.textContent
属性的索引执行突出显示。textContent
中的文字子集放在一个或多个<span class="highlighted">
中,而不更改父元素&#39; s { {1}}值,使得突出显示n次的文本位于n个嵌套textContent
元素内。<span class="highlighted">
字符串(包括空格)的给定索引处的值。
.textContent
&#13;
function highlight(parent, startoff, endoff) {
// Erm...
parent.textContent;
}
// Test cases
var starts = [
5, 44, 0, 50, 6, 100, 99, 50, 51, 52
];
var ends = [
20, 62, 4, 70, 10, 100, 101, 54, 53, 53
];
for (var i = 0; i < 10; i += 1) {
highlight(document.getElementById("target"),
starts[i], ends[i]);
}
&#13;
#target {
white-space: pre-wrap;
}
&#13;
答案 0 :(得分:4)
对开始/结束位置进行标准化以避免重叠。
通过这种方式,您将获得突出显示的位置,而不会嵌套/重叠范围。
用文本节点和HTML元素(例如<span>
)documentFragment
和.replaceChild()
混合替换文本节点会有所帮助:
let starts = [
5, 44, 0, 50, 6, 100, 99, 50, 51, 52
];
let ends = [
20, 62, 4, 70, 10, 100, 101, 54, 53, 53
];
let positions = [];
let normalizedPositions = [];
starts.forEach(function(position) {
positions.push({position, value: 1});
});
ends.forEach(function(position) {
positions.push({position, value: -1});
});
positions = positions.sort(function(a, b) {
return a.position - b.position ||
b.value - a.value
});
var currentSection = {from: 0, counter: 0};
for(position of positions) {
if (!currentSection.counter) {
if (position.value === -1) {
throw `inconsistent boundaries: closing before opening ${position.position}`;
}
currentSection.from = position.position;
}
currentSection.counter += position.value;
if (!currentSection.counter) {
normalizedPositions.push({
from: currentSection.from,
to: position.position
});
}
}
if (currentSection.counter) {
throw "last section has not been closed properly";
}
let parentNode = document.querySelector('p');
let textNodeToReplace = parentNode.childNodes[0];
let sourceText = textNodeToReplace.nodeValue;
let documentFragment = document.createDocumentFragment();
let withoutHighlightingStart = 0;
normalizedPositions.forEach(function (highlightRange) {
if (highlightRange.from> withoutHighlightingStart) {
let notHighlighted = createTextNode(sourceText.slice(withoutHighlightingStart, highlightRange.from));
documentFragment.appendChild(notHighlighted);
}
let highlighted = createHighlighted(sourceText.slice(highlightRange.from, highlightRange.to));
documentFragment.appendChild(highlighted);
withoutHighlightingStart = highlightRange.to;
});
let lastNotHighlighted = createTextNode(sourceText.slice(withoutHighlightingStart));
documentFragment.appendChild(lastNotHighlighted);
parentNode.replaceChild(documentFragment, textNodeToReplace);
function createTextNode(str) {
return document.createTextNode(str);
}
function createHighlighted(str) {
let span = document.createElement('span');
span.classList.add('highlight');
span.appendChild(createTextNode(str));
return span;
}
&#13;
.highlight {
background-color: yellow;
color: dark-blue;
}
&#13;
<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>
&#13;