How do I dynamically append a <span> tag into a specific location of the <p> tag?

本秂侑毒 提交于 2020-05-23 21:39:02

问题


In essence, I'm trying to implement a feature which highlights certain text when selected. This is strictly for the Google Chrome browser.

For example: Before selection:

<html>
    <body>
        <p>sample text</p>
    </body>
</html>

After selecting "text" from "sample text":

<html>
    <body>
        <p>sample <span class="state-highlighted">text</span> </p>
    </body>
</html>

JavaScript:

document.body.addEventListener("mousedown", (event) => {
  document.body.addEventListener("mouseup", (event) => {

    // Assume we have checked that mousedown position is different from mouseup position.
    // Not sure what to do after this.

  });
});

I could start with a simpler question: How do I insert a span element into a paragragh element, let's say on click?


回答1:


There is a Range.surroundContents method that would come handy here, but it will throw when selecting only part of an element.
So in your case it might be better to extract the content of the current Range, append it in your new node, and then insert that new node where the Range is:

document.getElementById('target').addEventListener('mouseup', e => {
  const sel = getSelection();
  const range = sel.getRangeAt(0);
  const highlighter = document.createElement('span');
  highlighter.classList.add('highlight');
  highlighter.append(range.extractContents());
  range.insertNode(highlighter);
})
.highlight { color: red; }
<p id="target">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>



回答2:


On mouseup, call window.getSelection() to get a Selection object. You can examine it to find the start and end text of the selection inside the <p>. Then replace the <p>'s HTML to surround that section of text with <span class="highlighted">:

const p = document.body.querySelector('p');
const origContent = p.textContent;
p.addEventListener('mousedown', () => {
  p.textContent = origContent;
});
p.addEventListener('mouseup', (e) => {
  const selection = window.getSelection();
  if (!selection) {
    return;
  }
  const range = selection.getRangeAt(0);
  // If user starts highlighting on the right, and drags mouse to the left,
  // endOffset will be smaller than startOffset:
  const startIndex = Math.min(range.startOffset, range.endOffset);
  const { length } = String(selection);
  const endIndex = startIndex + length;
  p.textContent = p.textContent;
  p.innerHTML = (
    p.textContent.slice(0, startIndex) +
    '<span class="highlighted">' +
    selection +
    '</span>' +
    p.textContent.slice(endIndex)
  );
});
.highlighted {
  background-color: orange;
}
<p>sample text sample text sample text sample text sample text sample text sample text sample text sample text</p>

If the user might select more than one part of the text at a time, and you'd want to highlight both discontiguous pieces of text, you can iterate over the ranges from 0 to selection.rangeCount and slice the original context to create the new HTML accordingly.



来源:https://stackoverflow.com/questions/59606037/how-do-i-dynamically-append-a-span-tag-into-a-specific-location-of-the-p-tag

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!