我的目标:
让用户在单个长字符串中突出显示不同的子字符串。
但是,一旦我用range.surroundContents(newNode)
突出显示了一个子字符串(newNode是带有黄色背景的span
),整个长字符串的innerHTML
就会发生变化-它开始包含span
元素;因此,如果用户希望在同一长字符串中的前一个突出显示的子字符串之后突出显示一个子字符串,则anchorOffset
将返回从前一个跨度after
开始的索引。
例如,在此长字符串中:
“排名第四的Privet Drive的Dursley先生和夫人很自豪地说他们很正常,非常感谢。”
此长句子由一个类名为p
的{{1}}包裹。如果noting
方法是子字符串“ Privet Drive”,那么当我想获取子字符串“ thank”的range.surroundContents()
时,答案错误地是 53 ,而正确的答案是答案应为 102 。
我应该怎么做?谢谢!!
P.S。我不想使用子字符串方法找到位置,谢谢!
window.getSelection().anchorOffset
然后将$(".noting").mouseup(function(e){
$("#noteContent").val("");/*flushing*/
curSentNum = $(this).attr("id").split("-")[1];
$('#curSentNum').val(curSentNum);
highlightLangName = $(this).attr("id").split("-")[2];
$('#highlightLangName').val(highlightLangName);
//console.log(".noting $(this).html()"+$(this).html()+" "+$(this).attr("id"));//id, for example: p-2-French
if (window.getSelection) {
highlightedText = window.getSelection().toString();
curAnchorOffset = window.getSelection().anchorOffset;
$('#anchorAt').val(curAnchorOffset);
$('#highlightLen').val(highlightedText.length);
}
else if (document.selection && document.selection.type != "Control") {
highlightedText = document.selection.createRange().text;
}
});
信息保存到db; db操作后,我将使用之前保留的变量立即调用此函数:
anchorAt
对于HTML树节点结构,请查看下面的注释(我不知道如何在此询问区域复制粘贴代码)。
答案 0 :(得分:1)
我用2种方法替换了您的突出显示文本的方法。 highlightTextNodes
在节点的内容中找到单词。搜索每个孩子。此外,我还实现了高光去除剂以显示其工作原理。我用span
标签替换了mark
。
let alreadyNoteStr = 'already';
let noteCounter = 0;
let elementId;
$('p.noting').mouseup(function(e) {
elementId = $(this).attr('id');
$('#noteContent').val(''); /*flushing*/
curSentNum = elementId.split('-')[1];
$('#curSentNum').val(curSentNum);
highlightLangName = elementId.split('-')[2];
$('#highlightLangName').val(highlightLangName);
//console.log(".noting $(this).html()"+$(this).html()+" "+$(this).attr("id"));//id, for example: p-2-French
if (window.getSelection) {
highlightedText = window.getSelection().toString();
curAnchorOffset = window.getSelection().anchorOffset;
$("#noteContent").val(highlightedText);
$('#anchorAt').val(curAnchorOffset);
$('#highlightLen').val(highlightedText.length);
highlight(elementId, highlightedText);
} else if (document.selection && document.selection.type != "Control") {
highlightedText = document.selection.createRange().text;
}
});
function highlightNoteJustSaved() {
let curI = noteCounter;
let anchorAt = parseInt($("#anchorAt").val());
let highlightLen = parseInt($("#highlightLen").val());
/*p to find, for example: p-2-French*/
let curP = document.getElementById('p-' + curSentNum.toString() + "-" + $("#highlightLangName").val());
let range = document.createRange();
rootNode = curP;
let childNode = rootNode.childNodes[0];
range.setStart(rootNode.childNodes[0], anchorAt);
range.setEnd(rootNode.childNodes[0], anchorAt + highlightLen);
var newNode = document.createElement("span");
newNode.style.cssText = "background-color:#ceff99"; //yellow
newNode.className = alreadyNoteStr;
newNode.setAttribute('id', 'already-note-' + curI.toString());
range.surroundContents(newNode);
}
/*
* Takes in an array of consecutive TextNodes and returns a document fragment with `word` highlighted
*/
function highlightTextNodes(nodes, word) {
if (!nodes.length) {
return;
}
let text = '';
// Concatenate the consecutive nodes to get the actual text
for (var i = 0; i < nodes.length; i++) {
text += nodes[i].textContent;
}
let fragment = document.createDocumentFragment();
while (true) {
// Tweak this if you want to change the highlighting behavior
var index = text.toLowerCase().indexOf(word.toLowerCase());
if (index === -1) {
break;
}
// Split the text into [before, match, after]
var before = text.slice(0, index);
var match = text.slice(index, index + word.length);
text = text.slice(index + word.length);
// Create the <mark>
let mark = document.createElement('mark');
mark.className = 'found';
mark.appendChild(document.createTextNode(match));
// Append it to the fragment
fragment.appendChild(document.createTextNode(before));
fragment.appendChild(mark);
}
// If we have leftover text, just append it to the end
if (text.length) {
fragment.appendChild(document.createTextNode(text));
}
// Replace the nodes with the fragment
nodes[0].parentNode.insertBefore(fragment, nodes[0]);
for (var i = 0; i < nodes.length; i++) {
let node = nodes[nodes.length - i - 1];
node.parentNode.removeChild(node);
}
}
/*
* Highlights all instances of `word` in `$node` and its children
*/
function highlight(id, word) {
let node = document.getElementById(id);
let children = node.childNodes;
let currentRun = [];
for (var i = 0; i < children.length; i++) {
let child = children[i];
if (child.nodeType === Node.TEXT_NODE) {
// Keep track of consecutive text nodes
currentRun.push(child);
} else {
// If we hit a regular element, highlight what we have and start over
highlightTextNodes(currentRun, word);
currentRun = [];
// Ignore text inside of our <mark>s
if (child.nodeType === Node.ELEMENT_NODE && child.className !== 'found') {
highlight(child, word);
}
}
}
// Just in case we have only text nodes as children
if (currentRun.length) {
highlightTextNodes(currentRun, word);
}
}
/*
* Removes all highlighted <mark>s from the given node
*/
function unhighlight(id) {
let node = document.getElementById(id);
let marks = [].slice.call(node.querySelectorAll('mark.found'));
for (var i = 0; i < marks.length; i++) {
let mark = marks[i];
// Replace each <mark> with just a text node of its contents
mark.parentNode.replaceChild(document.createTextNode(mark.childNodes[0].textContent), mark);
}
}
label {
display: block;
position: relative;
padding-left: 100px;
}
button {
margin-top: 20px;
margin-bottom: 20px;
padding: 10px;
}
label>span {
position: absolute;
left: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button type="button" onclick="unhighlight(elementId);">Unhighlight</button>
<div id="div-0" class="only-left-border">
<p class="lan-English noting" id="p-1-English">Mr. and Mrs. Dursley, of number four, Privet Drive, were proud to say that they were perfectly normal, thank you very much.</p>
</div>
<label><span>Content:</span><input type="text" id="noteContent"></input></label>
<label><span>Numer:</span><input type="text" id="curSentNum"></input></label>
<label><span>Language:</span><input type="text" id="highlightLangName"></input></label>
<label><span>Anchor:</span><input type="text" id="anchorAt"></input></label>
<label><span>Length:</span><input type="text" id="highlightLen"></input></label>