【问题标题】:Native javascript equivalent of jQuery :contains() selector本机 javascript 等效于 jQuery :contains() 选择器
【发布时间】:2013-07-21 21:01:51
【问题描述】:

我正在编写一个用户脚本,它将从包含特定字符串的页面中删除元素。

如果我正确理解了 jQuery 的 contains() 函数,它似乎是适合这项工作的正确工具。

不幸的是,由于我将在其上运行 UserScript 的页面不使用 jQuery,因此我无法使用 :contains()。你们有没有可爱的人知道这样做的本地方式是什么?

http://codepen.io/coulbourne/pen/olerh

【问题讨论】:

  • 继续add jQuery with your userscript。不要浪费时间尝试分段重建它。
  • 如果您准备放弃对某些浏览器的支持(我认为只是 IE7 - 编辑:也可能是 IE8),您可以使用与 JQuery 选择器非常相似的本机“document.querySelectorAll” . caniuse.com/#feat=queryselector

标签: javascript jquery userscripts


【解决方案1】:

这应该在现代浏览器中执行:

function contains(selector, text) {
  var elements = document.querySelectorAll(selector);
  return [].filter.call(elements, function(element){
    return RegExp(text).test(element.textContent);
  });
}

然后像这样使用它:

contains('p', 'world'); // find "p" that contain "world"
contains('p', /^world/); // find "p" that start with "world"
contains('p', /world$/i); // find "p" that end with "world", case-insensitive
...

【讨论】:

  • 可能使用Array.prototype.filter.call,而不是分配一个新数组。
  • 这是不正确的,因为它还包括所有子节点的结果。 IE。如果element 的子节点将包含text - element 将包含在contains 结果中;这是错误的。
【解决方案2】:

optional chaining operator 的超现代单行方法

[...document.querySelectorAll('*')].filter(element => element.childNodes?.[0]?.nodeValue?.match('❤'));

更好的方法是在所有子节点中搜索

[...document.querySelectorAll("*")].filter(e => e.childNodes && [...e.childNodes].find(n => n.nodeValue?.match("❤")))

【讨论】:

    【解决方案3】:

    如果你想像jQuery那样实现contains方法exaclty,这就是你需要的

    function contains(elem, text) {
        return (elem.textContent || elem.innerText || getText(elem)).indexOf(text) > -1;
    }
    
    function getText(elem) {
        var node,
            ret = "",
            i = 0,
            nodeType = elem.nodeType;
    
        if ( !nodeType ) {
            // If no nodeType, this is expected to be an array
            for ( ; (node = elem[i]); i++ ) {
                // Do not traverse comment nodes
                ret += getText( node );
            }
        } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
            // Use textContent for elements
            // innerText usage removed for consistency of new lines (see #11153)
            if ( typeof elem.textContent === "string" ) {
                return elem.textContent;
            } else {
                // Traverse its children
                for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
                    ret += getText( elem );
                }
            }
        } else if ( nodeType === 3 || nodeType === 4 ) {
            return elem.nodeValue;
        }
        // Do not include comment or processing instruction nodes
    
        return ret;
    };
    

    来源:Sizzle.js

    【讨论】:

      【解决方案4】:

      原始问题来自2013

      这是一个更较旧的解决方案,也是最快的解决方案,因为主要工作负载由浏览器引擎而不是完成JavaScript 引擎

      TreeWalker API 已经存在很长时间了,IE9 是最后一个实现它的浏览器...在 2011

      所有那些“现代”和“超现代”querySelectorAll("*") 需要处理所有节点每个节点上进行字符串比较.

      TreeWalker API 只为您提供 #text 节点,然后您可以对它们做您想做的事情。

      您也可以使用 NodeIterator API,但 TreeWalker is faster

        function textNodesContaining(txt, root = document.body) {
            let nodes = [],
                node, 
                tree = document.createTreeWalker(
                                  root, 
                                     4, // NodeFilter.SHOW_TEXT
                                     {
                                       node: node => RegExp(txt).test(node.data)
                                     });
            while (node = tree.nextNode()) { // only return accepted nodes
              nodes.push(node);
            }
            return nodes;
        }
      

      用法

      textNodesContaining(/Overflow/);
      
      textNodesContaining("Overflow").map(x=>console.log(x.parentNode.nodeName,x));
      
      // get "Overflow" IN A parent
      textNodesContaining("Overflow")
         .filter(x=>x.parentNode.nodeName == 'A')
         .map(x=>console.log(x));
      
      // get "Overflow" IN A ancestor
      textNodesContaining("Overflow")
         .filter(x=>x.parentNode.closest('A'))
         .map(x=>console.log(x.parentNode.closest('A')));
      
      

      【讨论】:

        【解决方案5】:

        这是现代方法

        function get_nodes_containing_text(selector, text) {
            const elements = [...document.querySelectorAll(selector)];
        
            return elements.filter(
              (element) =>
                element.childNodes[0]
                && element.childNodes[0].nodeValue
                && RegExp(text, "u").test(element.childNodes[0].nodeValue.trim())
            );
          }
        

        【讨论】:

          【解决方案6】:

          嗯,jQuery 配备了一个 DOM 遍历引擎,它的运行比我将要向您展示的那个要好得多,但它可以解决问题。

          var items = document.getElementsByTagName("*");
          for (var i = 0; i < items.length; i++) {
            if (items[i].innerHTML.indexOf("word") != -1) { 
              // Do your magic
            }
          }
          

          如果你愿意,可以将它包装在一个函数中,但我强烈建议使用 jQuery 的实现。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2012-01-23
            • 2019-12-03
            • 1970-01-01
            • 2011-09-17
            • 1970-01-01
            • 2020-10-28
            • 2012-09-27
            相关资源
            最近更新 更多