0

我有一个 HTML 文档:

<html>
  <body>
    <p>
      A funny joke:
      <ul>
        <li>do you know why six is afraid of seven?
        <li>because seven ate nine.
      </ul>
      Oh, so funny!
    </p>
  </body>
</html>

现在我想识别“七”的第一次出现并用

<span id="link1" class="link">

如何实现?

您是否必须解析 DOM 树或者是否可以在正文部分中获取整个代码然后搜索单词?

在这两种情况下,当我在某处找到这个词之后,你如何识别它并将它的 DOM-parent 更改为 span(我想这是必须要做的)然后添加提到的属性?

这不是我期望的代码,而是什么方法或概念可以完成这项工作。

而且我对框架解决方案不是很感兴趣,而是对纯 JavaScript 方式感兴趣。

4

3 回答 3

2

这是我几年前编写的一个函数,用于搜索特定文本并突出显示它们(将命中放在span具有特定类名的 a 中)。

它遍历 DOM 树,检查文本内容。每当它找到包含所查找文本的文本节点时,它将用三个新节点替换该文本节点:

  1. 一个带有匹配前文本的文本节点,
  2. 一个(新创建的)span包含匹配文本的元素,
  3. 和一个文本节点,其中包含匹配后的文本。

这是我拥有的功能。它是较大脚本文件的一部分,但也应该独立运行。(我已经注释掉了ensureElementVisible使元素可见的调用,因为脚本也具有折叠和扩展功能)。

它做了一件您可能不需要的(其他)事情:它将搜索文本转换为匹配多个单词中的任何一个的正则表达式。

function findText(a_text, a_top) {
    // Go through *all* elements below a_top (if a_top is undefined, then use the body)
    //  and check the textContent or innerText (only if it has textual content!)
    var rexPhrase = new RegExp(a_text.replace(/([\\\/\*\?\+\.\[\]\{\}\(\)\|\^\$])/g, '\\$1').replace(/\W+/g, '\\W*')
                                    , 'gi');
    var terms = [];
    var rexSearchTokens = /[\w]+/g;
    var match;
    while(match = rexSearchTokens.exec(a_text)) {
        terms.push(match[0]);
    }
    var rexTerm = new RegExp('\\b(' + terms.join('|') + ')', 'gi');

    var hits = [];
    walkDOMTree(a_top || document.body,
                function search(a_element) {
                    if (a_element.nodeName === '#text') {
                        if(rexPhrase.test(a_element.nodeValue)) {
//                          ensureElementVisible(a_element, true);
                            hits.push(a_element);
                        }
                    }
                });

    // highlight the search terms in the found elements
    for(var i = 0; i < hits.length; i++) {
        var hit = hits[i];
        var parent = hit.parentNode;

        if (parent.childNodes.length === 1) {
            // Remove the element from the hit list
            hits.splice(i, 1);

            var text = hit.nodeValue;
            parent.removeChild(hit);
            var match, prevLastIndex = 0;
            while(match = rexTerm.exec(text)) {
                parent.appendChild(document.createTextNode(text.substr(prevLastIndex, match.index - prevLastIndex)));
                var highlightedTerm = parent.appendChild(document.createElement('SPAN'));
                highlightedTerm.className = 'search-hit';
                highlightedTerm.appendChild(document.createTextNode(match[0]));
                prevLastIndex = match.index + match[0].length;

                // Insert the newly added element into the hit list
                hits.splice(i, 0, highlightedTerm);
                i++;
            }
            parent.appendChild(document.createTextNode(text.substr(prevLastIndex)));

            // Account for the removal of the original hit node
            i--;
        }
    }

    return hits;
}
于 2011-03-25T15:21:20.003 回答
2

您需要找到一个类型为 TEXT_NODE (3) 的 DOM 节点并包含您预期的单词。当您需要将该节点拆分为三个时。

第一个是 TEXT_NODE,其中包含您搜索的单词之前的文本,第二个是包含您搜索的单词的 SPAN 节点,第三个是另一个包含原始节点尾部的 TEXT_NODE(都在搜索的单词之后)。

这是一个源代码...

<html>
   <head>
      <style type="text/css">
         .link {
            color: red;
         }
      </style>
   </head>
  <body>
    <p>
      A funny joke:
      <ul>
        <li>do you know why six is afraid of seven?
        <li>because seven ate nine.
      </ul>
      Oh, so funny!
    </p>
    <script type="text/javascript">
       function search(where, what) {
         var children = where.childNodes;
         for(var i = 0, l = children.length; i < l; i++) {
            var child = children[i], pos;
            if(child.nodeType == 3 && (pos = child.nodeValue.indexOf(what)) != -1) { // a TEXT_NODE
               var value = child.nodeValue;
               var parent = child.parentNode;
               var start = value.substring(0, pos);
               var end = value.substring(pos + what.length);
               var span = document.createElement('span');

               child.nodeValue = start;
               span.className = 'link';
               span.id = 'link1';
               span.innerHTML = what;
               parent.appendChild(span);
               parent.appendChild(document.createTextNode(end));
               return true;
            } else
               if(search(child, what))
                  break;
         }
         return false;
       }
       search(document.getElementsByTagName('body')[0], 'seven');
    </script>
  </body>
</html>
于 2011-03-25T14:33:12.693 回答
0

我发现了以下问题: Find text string using jQuery?

这似乎接近你想要做的事情。现在您是尝试仅包装文本“seven”还是尝试包装 <li> 的全部内容?

于 2011-03-23T13:39:04.940 回答