忽略 window 选择中的跨度标记以获取开始和结束索引

Ignore span stag in window selection to get the start and end index

我有一个 html 标签,它是

<span>This is first text<span class="ignore">Second</span> This is third text<span>

我正在尝试从 selected 文本中获取开始和结束索引。当我 select third 我得到开始和结束索引为 34 39 但我预计 27 32

我试过下面的方法

export const findTextRange = (element) => {
  if (!element) return;
  let start = 0, end = 0;
  let sel, range, priorRange, text;
  if (typeof window.getSelection != "undefined") {
    sel = window.getSelection();
    text = sel + '';
    if (window.getSelection().rangeCount <= 0) {
      return;
    }
    range = window.getSelection().getRangeAt(0);
    priorRange = range.cloneRange();
    priorRange.selectNodeContents(element);
    priorRange.setEnd(range.startContainer, range.startOffset);
    start = priorRange.toString().length;
    end = start + (sel + '').length;
  } else if (typeof document.selection !== "undefined" &&
    (sel = document.selection).type !== "Control") {
    text = sel + '';
    range = sel.createRange();
    priorRange = document.body.createTextRange();
    priorRange.moveToElementText(element);
    priorRange.setEndPoint("EndToStart", range);
    start = priorRange.text.length;
    end = start + (sel + '').length;
  }
  return { start, end, text };
}

有什么方法可以忽略 span 元素 ignore class.

存储初始HTML,然后删除所有具有.ignore class:

的元素
const html = element.innerHTML;
element.querySelectorAll('.ignore').forEach((e) => e.remove());

得到范围后,恢复原来的HTML:

element.innerHTML = html;

片段

const findTextRange = (element) => {
  if (!element) return;
  const html = element.innerHTML; // store original HTML
  element.querySelectorAll('.ignore').forEach((e) => e.remove()); // remove ignore elements
  
  let start = 0, end = 0;
  let sel, range, priorRange, text;
  if (typeof window.getSelection != "undefined") {
    sel = window.getSelection();
    text = sel + '';
    if (window.getSelection().rangeCount <= 0) {
      return;
    }
    range = window.getSelection().getRangeAt(0);
    priorRange = range.cloneRange();
    priorRange.selectNodeContents(element);
    priorRange.setEnd(range.startContainer, range.startOffset);
    start = priorRange.toString().length;
    end = start + (sel + '').length;
  } else if (typeof document.selection !== "undefined" &&
    (sel = document.selection).type !== "Control") {
    text = sel + '';
    range = sel.createRange();
    priorRange = document.body.createTextRange();
    priorRange.moveToElementText(element);
    priorRange.setEndPoint("EndToStart", range);
    start = priorRange.text.length;
    end = start + (sel + '').length;
  }
  element.innerHTML = html;  // restore HTML
  console.log(start, end, text);
  return { start, end, text };
}

document.querySelector('#P').addEventListener('click', function() {findTextRange(this)});
<span id="P">This is first text<span class="ignore">Second</span> This is third text<span>