【问题标题】:prototype.js highlight words. DOM traversing correctly and efficientlyprototype.js 突出显示单词。正确高效地遍历 DOM
【发布时间】:2011-12-28 00:34:54
【问题描述】:

我想在页面加载后突出显示我的 HTML 页面中的特定单词。我不想用笨蛋:

document.innerHTML = document.innerHTML.replace(.....);

我想遍历每个 DOM 节点,找出那些包含文本的节点,然后只修改那些单个节点的 innerHTML。这是我想出的:

function highlightSearchTerms(sword) {
$$('body').map(Element.extend).first().descendants().each(function (el) {
    if (el.nodeType == Node.ELEMENT_NODE && el.tagName != 'TD') {
        //$A(el.childNodes).each(function (onlyChild) {
            //if (onlyChild.nodeType == Node.TEXT_NODE) {
                //console.log(onlyChild);
                el.innerHTML = el.innerHTML.replace(new RegExp('('+sword+')', 'gi'), '<span class="highlight">$1</span>');
            //}
        //});
    }
});
//document.body.innerHTML.replace(new RegExp('('+sword+')', 'gi'), '<span class="highlight">$1</span>');
}

它现在可以正常工作,但是效率非常低,并且几乎不比上面的单行好,因为它可能对同一文本进行多次替换。 (嗯...,还是没有?)

如果您取消注释已注释的内容并将el.innerHTML.replace 更改为onlyChild.textContent.replace,它几乎可以正常工作,但修改 textContent 不会创建新的 span 作为元素,而是将 HTML 内容添加为文本。

我的问题/要求是找到一种方法来逐个突出显示文档中遍历元素的单词。

【问题讨论】:

    标签: javascript html prototypejs highlight


    【解决方案1】:

    这工作又快又干净:

    function highlightSearchTerms(sword) {
    $$('body').map(Element.extend).first().descendants().each(function (el) {
        if (el.nodeType == Node.ELEMENT_NODE && el.tagName != 'TEXTAREA' && el.tagName != 'INPUT' && el.tagName != 'SCRIPT') {
            $A(el.childNodes).each(function (onlyChild) {
                var pos = onlyChild.textContent.indexOf(sword);
                if (onlyChild.nodeType == Node.TEXT_NODE && pos >= 0) {
                    //console.log(onlyChild);
                    var spannode = document.createElement('span');
                    spannode.className = 'highlight';
                    var middlebit = onlyChild.splitText(pos);
                    var endbit = middlebit.splitText(sword.length);
                    var middleclone = middlebit.cloneNode(true);
                    spannode.appendChild(middleclone);
                    middlebit.parentNode.replaceChild(spannode, middlebit);
    
                    //onlyChild. = el.innerHTML.replace(new RegExp('('+sword+')', 'gi'), '<span class="highlight">$1</span>');
                }
            });
        }
    });
    }
    

    但我无法理解它究竟是如何工作的。这似乎是一条神奇的线:

    middlebit.parentNode.replaceChild(spannode, middlebit);
    

    【讨论】:

    • 是我发布的 jquery 的原型端口:) 我要继续为我自己的网站偷这个。
    【解决方案2】:

    前段时间我将一个从 jQuery 转换为 PrototypeJS :

    Element.addMethods({
      highlight: function(element, term, className) {
        function innerHighlight(element, term, className) {
          className = className || 'highlight';
          term = (term || '').toUpperCase();
    
          var skip = 0;
          if ($(element).nodeType == 3) {
            var pos = element.data.toUpperCase().indexOf(term);
            if (pos >= 0) {
              var middlebit = element.splitText(pos),
                  endbit = middlebit.splitText(term.length),
                  middleclone = middlebit.cloneNode(true),
                  spannode = document.createElement('span');
    
              spannode.className = 'highlight';
              spannode.appendChild(middleclone);
              middlebit.parentNode.replaceChild(spannode, middlebit);
              skip = 1;
            }
          }
          else if (element.nodeType == 1 && element.childNodes && !/(script|style)/i.test(element.tagName)) {
            for (var i = 0; i < element.childNodes.length; ++i)
              i += innerHighlight(element.childNodes[i], term);
          }
          return skip;
        }
        innerHighlight(element, term, className);
        return element;
      },
      removeHighlight: function(element, term, className) {
        className = className || 'highlight';
        $(element).select("span."+className).each(function(e) {
          e.parentNode.replaceChild(e.firstChild, e);
        });
        return element;
      }
    });
    

    您可以像这样在每个元素上使用它:

    $("someElementId").highlight("foo", "bar");
    

    ,并使用您选择的类名。您也可以删除高光。

    【讨论】:

      【解决方案3】:

      如果您使用的是 Fabien 发布的 原型版本,请务必添加 className 作为调用 innerHighlight 的参数:

      i += innerHighlight(element.childNodes[i], term)
      

      需要

      i += innerHighlight(element.childNodes[i], term, className)
      

      如果您关心您的亮点的自定义类名。

      【讨论】:

        【解决方案4】:

        获取 $(document.body) 并进行搜索/替换并围绕该术语包装一个跨度,然后一次性交换整个 $(document.body)。把它当作一个大字符串,忘记 DOM。这样,您只需更新 DOM 一次。应该很快。

        【讨论】:

        • 我认为如果他想要突出显示的单词碰巧是这样的:“输入”或“跨度”或“值”,基本上任何可能在标记中的东西,而不是显示的文字
        • 这正是我现在注意到的情况。不行。
        【解决方案5】:

        我找到了一个可以做你想做的事情的脚本(看起来相当快),它不是特定于任何库的,所以你可能想要修改它:

        http://www.nsftools.com/misc/SearchAndHighlight.htm

        您在上面提供的方法(尽管已被注释掉)在替换可能位于 html 元素内的项目时会出现问题。即 ` 搜索和替换可能会“突出显示”“事物”,而这不是您想要的。

        这是一个基于 Jquery 的高亮脚本:

        http://johannburkard.de/blog/programming/javascript/highlight-javascript-text-higlighting-jquery-plugin.html

        看起来很难转换成原型。

        【讨论】:

        • 我知道nsftools.com/misc/SearchAndHighlight.htm 并一直使用它直到今天,当我发现它不能以某种方式与 Ajax 一起工作时。它执行相同的 innerHTML 处理 - 只是更花哨。
        • 我也知道johannburkard.de/blog/programming/javascript/…,甚至在你提出建议之前我就已经听从了你的建议。我已经让它基于这个 jQuery 代码工作,但我仍然不明白它是如何工作的。请参阅下面我自己的答案。
        猜你喜欢
        • 2015-07-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-08-07
        • 2012-08-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多