javascript在遇到意外的anchorOffset时执行多个createrange()

时间:2019-01-27 23:17:40

标签: javascript

我的目标:

  

让用户在单个长字符串中突出显示不同的子字符串。

但是,一旦我用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树节点结构,请查看下面的注释(我不知道如何在此询问区域复制粘贴代码)。

1 个答案:

答案 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>