本机javascript相当于jQuery:contains()选择器

时间:2013-07-22 23:37:54

标签: javascript jquery userscripts

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

如果我正确理解jQuery的contains()函数,它似乎是正确的工具。

不幸的是,由于我将运行UserScript的页面不使用jQuery,我不能使用:contains()。你们中的任何一个人都知道这样做的原生方式是什么?

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

6 个答案:

答案 0 :(得分:25)

这应该在现代浏览器中实现:

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
...

答案 1 :(得分:4)

如果你想完全像jQuery一样实现contains方法,那么这就是你需要的东西

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

答案 2 :(得分: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 :(得分:2)

原始问题来自 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
                                            {
                                              acceptNode: 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')));

答案 4 :(得分:1)

嗯,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的实现。

答案 5 :(得分:0)

这是现代方法

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())
    );
  }
相关问题