Как обернуть ключевые слова DOM в тег span - PullRequest
1 голос
/ 23 апреля 2019

Я пишу сценарий JavaScript, который будет обходить DOM и обернуть определенное ключевое слово в тег <span>.Я хочу, чтобы мой script обернул все вхождения слова pan в <span>, чтобы я мог стилизовать его, используя <span style='color: red'.На самом деле я не хочу использовать слово pan, я просто использую его в качестве примера.

Я уже рассмотрел много подобных сообщений здесь, но ни один из них не решил мою проблему.Большинство из них являются либо ядерными, либо слишком сложными и запутанными, либо слишком упрощенными и не работают так, как я планировал.

Вот что я написал до сих пор:

<html>
  <body>
    <p>My <span style='font-weight: bold'>favorite</span> kitchen item is the pan.</p>
    <p>A pan can also be used as a weapon.</p>
    <script>
      // walk the document body
      function walk (node) {
        // if text node
        if (node.nodeType == 3) {
          // will always be an element
          const parent = node.parentNode;
          
          // ignore script and style tags
          const tagName = parent.tagName;
          if (tagName !== 'SCRIPT' && tagName !== 'STYLE') {
            
            // wrap occurrences of 'pan' in a red `<span>` tag
            const span = '<span style="color: red">pan</span>';
            parent.innerHTML = parent.innerHTML.replace (/pan/g, span)
          }
        }
        node = node.firstChild;
        while (node) {
          walk (node);
          node = node.nextSibling;
        }
      }
      walk (document.body)
    </script>
  </body>
</html>

Этот код выполняется в большинстве случаев так, как задумано.Однако в этом примере это не так.Если бы вы запустили этот код, это было бы результатом.

Я знаю, что является причиной этого.Однако я не знаю, как ее решить.

Два текстовых узла, My и kitchen item is the pan., имеют родительский элемент со следующим innerHTML: My <span style="font-weight: bold">favorite</span> kitchen item is the pan. "pan" in <span> заменяется и вызывает проблему.

Если я использую parentNode.textContent вместо parentNode.innerHTML, он не переносится в тег <span>, он вставляется как видимый текст.

Я понимаю, что это можно исправить, изменив /pan/g на /\bpan\b/g, но это исправляет только тот пример, который я создал.Мне нужно, чтобы тег <span> вставлялся только в текстовое содержимое, а не в имена тегов или другой HTML.

Что мне делать?

1 Ответ

2 голосов
/ 23 апреля 2019

Поиск заданного htmlString с помощью экранированной строки поиска. Это (с соответствующим экранированием) поможет избежать таких проблем, как сопоставление тегов HTML (например, <s pan >) или подстрок (например, Pan dora).

/*
highlight(selector, string)
@ Params:
  selector [String]: Same syntax as CSS/jQuery selector
  string   [String]: Seach string
*/
// A: Get the htmlString of the target's content
// B: Escape the search string
// C: Create a RegExp Object of the escaped search string
// D: Find and replace all matches with match wrapped in a <mark>
// E: Remove original HTML
// F: Insert new HTML
function highlight(selector, string) {
  let dom = document.querySelector(selector);
  let str = dom.innerHTML; //A
  let esc = `(?!(?:[^<]+>|[^>]+<\\/a>))\\b(${string})\\b`; //B
  let rgx = new RegExp(esc, "gi"); //C
  let txt = str.replace(rgx, `<mark>$1</mark>`); //D
  dom.innerHTML = ''; //E 
  dom.insertAdjacentHTML('beforeend', txt); //F
}

highlight('body', "pan");
<html>

<body>
  <p>My <span style='font-weight: bold'>favorite</span> kitchen item is the pan.</p>
  <p>A pan can also be used as a weapon.</p>
  <p>Pan was the Greek god of the wild.</p>
  <p>Eboli was breifly a pandemic threat.</p>

</body>

</html>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...