簡體   English   中英

javascript在遇到意外的anchorOffset時執行多個createrange()

[英]javascript doing multiple createrange() while encountering unexpected anchorOffset

我的目標:

讓用戶在單個長字符串中突出顯示不同的子字符串。

但是,一旦我用range.surroundContents(newNode)突出顯示了一個子字符串(newNode 是一個黃色背景的span ),整個長字符串的innerHTML發生了變化——它開始包含span元素; 因此,如果用戶想在同一長字符串中突出顯示前一個突出顯示的子字符串之后的子字符串, anchorOffset將返回從前一個跨度after開始的索引。

例如,在這個長字符串中:

“女貞路四號的德思禮夫婦很自豪地說他們完全正常,非常感謝你們。”

這個長句子被一個p包裹着,它的類名是noting 如果range.surroundContents()方法是子字符串“Privet Drive”,那么,當我想獲取子字符串“thank”的window.getSelection().anchorOffset時,錯誤的答案是53而正確的答案應該是102 我應該怎么做? 謝謝!!

PS我不想用substring方法找位置,謝謝!

$(".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;
    }

});

然后我將anchorAt信息保存到db; 在 db 操作之后,我會立即使用之前保留的變量調用這個函數:

function highlightNoteJustSaved(){
    var curI = noteCounter;
    var anchorAt = parseInt($("#anchorAt").val());
    var highlightLen = parseInt($("#highlightLen").val());
    /*p to find, for example: p-2-French*/
    var curP = document.getElementById('p-'+curSentNum.toString()+"-"+$("#highlightLangName").val());
    var range = document.createRange();
    root_node = curP;

    range.setStart(root_node.childNodes[0], anchorAt);
    range.setEnd(root_node.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);
}

對於 HTML 樹節點結構,請看下面的評論(我沒有弄清楚如何在此詢問區域復制粘貼代碼)。

我用兩種方法替換了您突出顯示文本的方法。 highlightTextNodes在節點的內容中查找單詞。 尋找每一個孩子。 我還實現了一個高光去除器來展示它是如何工作的。 我用mark標簽替換了span

 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>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM