【问题标题】:Javascript .querySelector find <div> by innerTEXTJavascript .querySelector 通过 innerTEXT 查找 <div>
【发布时间】:2016-09-03 01:31:13
【问题描述】:

如何找到带有特定文本的 DIV?例如:

<div>
SomeText, text continues.
</div>

尝试使用这样的东西:

var text = document.querySelector('div[SomeText*]').innerTEXT;
alert(text);

但它当然行不通。我该怎么做?

【问题讨论】:

标签: javascript innertext selectors-api


【解决方案1】:

OP 的问题是关于纯 JavaScript 而不是 jQuery。 虽然有很多答案,而且我喜欢@Pawan Nogariya answer,但请查看这个替代方案。

您可以在 JavaScript 中使用 XPATH。有关 MDN 文章 here 的更多信息。

document.evaluate() 方法评估 XPATH 查询/表达式。因此,您可以在那里传递 XPATH 表达式,遍历 HTML 文档并找到所需的元素。

在 XPATH 中,您可以通过如下文本节点选择一个元素,获取具有以下文本节点的 div

//div[text()="Hello World"]

要获取包含一些文本的元素,请使用以下命令:

//div[contains(., 'Hello')]

XPATH 中的contains() 方法将节点作为第一个参数,将要搜索的文本作为第二个参数。

检查这个 plunk here,这是在 JavaScript 中使用 XPATH 的示例

这是一个代码sn-p:

var headings = document.evaluate("//h1[contains(., 'Hello')]", document, null, XPathResult.ANY_TYPE, null );
var thisHeading = headings.iterateNext();

console.log(thisHeading); // Prints the html element in console
console.log(thisHeading.textContent); // prints the text content in console

thisHeading.innerHTML += "<br />Modified contents";  

如您所见,我可以抓取 HTML 元素并随意修改它。

【讨论】:

  • 谢谢!效果很好!但是如果我只需要从这个文本中抓取一个单词,如何“console.log”“thisHeading.textContent”?例如:'//div[contains(., \'/You login (.*) times this session/\')]' 然后 alert(thisHeading.textContent.$1)
  • 好的,我这样做:alert(thisHeading.textContent.replace(/.*You have login (.*) times.*/,'$1')) ;
  • @passwd,你不能那样做。 XPATH 1.0 不支持正则表达式(.evaluate() 使用。如果我错了,请有人纠正我),所以首先,你不能搜索与正则表达式匹配的东西。其次,.textContent 属性返回元素的文本节点。如果你想从这个文本中获取一个值,你应该明确地处理它,可能是通过创建某种与正则表达式匹配并返回组中匹配值的函数。为此在单独的线程上提出一个新问题。
  • Internet Explorer:不支持。但在 Edge 中支持。我不确定这意味着什么,版本方面。
  • 如果我要查找的元素丢失,应该如何处理错误?
【解决方案2】:

您可以使用这个非常简单的解决方案:

Array.from(document.querySelectorAll('div'))
  .find(el => el.textContent === 'SomeText, text continues.');
  1. Array.from 会将 NodeList 转换为数组(有多种方法可以做到这一点,例如扩展运算符或切片)

  2. 现在作为数组的结果允许使用Array.find 方法,然后您可以放入任何谓词。您还可以使用正则表达式或任何您喜欢的方式检查 textContent。

请注意,Array.fromArray.find 是 ES2015 功能。无需转译器即可与 IE10 等旧版浏览器兼容:

Array.prototype.slice.call(document.querySelectorAll('div'))
  .filter(function (el) {
    return el.textContent === 'SomeText, text continues.'
  })[0];

【讨论】:

  • 如果您想查找多个元素,请将find 替换为filter
  • [].slice.call( ... ) 更简单?
【解决方案3】:

因为你已经在 javascript 中问过了,所以你可以有这样的东西

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

然后这样称呼它

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

【讨论】:

  • 似乎这样可行,但作为回报我只得到这个:[object HTMLDivElement],[object HTMLDivElement]
  • 是的,您将获得包含匹配文本的 div,然后您可以在其中调用类似 foundDivs[0].innerText 的内部文本方法,就这么简单
【解决方案4】:

此解决方案执行以下操作:

  • 使用ES6扩展运算符将所有divs的NodeList转换为数组。

  • 如果div 包含 查询字符串,则提供输出,而不仅仅是如果它恰好等于 查询字符串(其他一些答案会发生这种情况)。例如它不仅应该为“SomeText”提供输出,还应该为“SomeText,文本继续”提供输出。

  • 输出整个div 内容,而不仅仅是查询字符串。例如对于“SomeText,文本继续”,它应该输出整个字符串,而不仅仅是“SomeText”。

  • 允许多个divs 包含字符串,而不仅仅是一个div

[...document.querySelectorAll('div')]      // get all the divs in an array
  .map(div => div.innerHTML)               // get their contents
  .filter(txt => txt.includes('SomeText')) // keep only those containing the query
  .forEach(txt => console.log(txt));       // output the entire contents of those
<div>SomeText, text continues.</div>
<div>Not in this div.</div>
<div>Here is more SomeText.</div>

【讨论】:

  • 我喜欢这个。干净、简洁、易于理解——同时兼顾。
  • 肯定是非常低效?想一想innerHTML 对您的顶级&lt;div&gt;s 有多大。您应该首先过滤掉包含孩子的divs。还怀疑document.getElementsByTagName('div') 可能更快,但我会确定基准。
  • 这对我来说很棒,我可以在开始时设置一个很好的选择器,因为我已经知道它只能在表格中,很酷,谢谢
【解决方案5】:

你最好看看你是否有你正在查询的 div 的父元素。如果是这样,请获取父元素并执行element.querySelectorAll("div")。获得 nodeList 后,在 innerText 属性上对其应用过滤器。假设我们正在查询的 div 的父元素有一个 idcontainer。您通常可以直接从 id 访问容器,但让我们以正确的方式进行。

var conty = document.getElementById("container"),
     divs = conty.querySelectorAll("div"),
    myDiv = [...divs].filter(e => e.innerText == "SomeText");

就是这样。

【讨论】:

  • 这对我有用,但使用的是 innerHTML 而不是 innerText
【解决方案6】:

在 2021 年遇到这个问题,我发现使用 XPATH 过于复杂(需要学习其他东西),而本来应该很简单的东西。

想出了这个:

function querySelectorIncludesText (selector, text){
  return Array.from(document.querySelectorAll(selector))
    .find(el => el.textContent.includes(text));
}

用法:

querySelectorIncludesText('button', 'Send')

请注意,我决定使用includes,而不是严格比较,因为这是我真正需要的,请随时适应。

如果你想支持所有浏览器,你可能需要这些 polyfill:

  /**
   * String.prototype.includes() polyfill
   * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes#Polyfill
   * @see https://vanillajstoolkit.com/polyfills/stringincludes/
   */
  if (!String.prototype.includes) {
    String.prototype.includes = function (search, start) {
      'use strict';

      if (search instanceof RegExp) {
        throw TypeError('first argument must not be a RegExp');
      }
      if (start === undefined) {
        start = 0;
      }
      return this.indexOf(search, start) !== -1;
    };
  }

【讨论】:

    【解决方案7】:

    如果你不想使用 jquery 或类似的东西,那么你可以试试这个:

    function findByText(rootElement, text){
        var filter = {
            acceptNode: function(node){
                // look for nodes that are text_nodes and include the following string.
                if(node.nodeType === document.TEXT_NODE && node.nodeValue.includes(text)){
                     return NodeFilter.FILTER_ACCEPT;
                }
                return NodeFilter.FILTER_REJECT;
            }
        }
        var nodes = [];
        var walker = document.createTreeWalker(rootElement, NodeFilter.SHOW_TEXT, filter, false);
        while(walker.nextNode()){
           //give me the element containing the node
           nodes.push(walker.currentNode.parentNode);
        }
        return nodes;
    }
    
    //call it like
    var nodes = findByText(document.body,'SomeText');
    //then do what you will with nodes[];
    for(var i = 0; i < nodes.length; i++){ 
        //do something with nodes[i]
    } 
    

    一旦您在包含文本的数组中拥有节点,您就可以对它们进行一些操作。像提醒每个人或打印到控制台。需要注意的是,这可能不一定会抓取 div 本身,它会抓取包含您要查找的文本的 textnode 的父节点。

    【讨论】:

      【解决方案8】:

      由于数据属性中的文本长度没有限制,请使用数据属性!然后你可以使用常规的 css 选择器来选择你想要的元素。

      for (const element of document.querySelectorAll("*")) {
        element.dataset.myInnerText = element.innerText;
      }
      
      document.querySelector("*[data-my-inner-text='Different text.']").style.color="blue";
      <div>SomeText, text continues.</div>
      <div>Different text.</div>

      理想情况下,您在文档加载时执行数据属性设置部分,并稍微缩小 querySelectorAll 选择器以提高性能。

      【讨论】:

        【解决方案9】:

        这里已经有很多很棒的解决方案。然而,为了提供一种更精简的解决方案,并且与 querySelector 行为和语法的理念保持一致,我选择了一种使用几个原型函数扩展 Object 的解决方案。这两个函数都使用正则表达式来匹配文本,但是,可以提供一个字符串作为松散的搜索参数。

        只需实现以下功能:

        // find all elements with inner text matching a given regular expression
        // args: 
        //      selector: string query selector to use for identifying elements on which we 
        //                should check innerText
        //      regex: A regular expression for matching innerText; if a string is provided,
        //             a case-insensitive search is performed for any element containing the string.
        Object.prototype.queryInnerTextAll = function(selector, regex) {
            if (typeof(regex) === 'string') regex = new RegExp(regex, 'i'); 
            const elements = [...this.querySelectorAll(selector)];
            const rtn = elements.filter((e)=>{
                return e.innerText.match(regex);
            });
            
            return rtn.length === 0 ? null : rtn
        }
        
        // find the first element with inner text matching a given regular expression
        // args: 
        //      selector: string query selector to use for identifying elements on which we 
        //                should check innerText
        //      regex: A regular expression for matching innerText; if a string is provided,
        //             a case-insensitive search is performed for any element containing the string.
        Object.prototype.queryInnerText = function(selector, text){
            return this.queryInnerTextAll(selector, text)[0];
        }
        

        实现这些功能后,您现在可以进行如下调用:

        • document.queryInnerTextAll('div.link', 'go');
          这将找到包含 link 类的所有 div,innerText 中带有单词 go(例如,Go Left往下走往右走往下走od
        • document.queryInnerText('div.link', 'go');
          这将与上面的示例完全相同,只是它只返回第一个匹配元素。
        • document.queryInnerTextAll('a', /^Next$/);
          查找所有带有确切文本Next(区分大小写)的链接。这将排除包含单词 Next 以及其他文本的链接。
        • document.queryInnerText('a', /next/i);
          查找包含单词next的第一个链接,无论大小写(例如Next PageGo to next
        • e = document.querySelector('#page');
          e.queryInnerText('button', /Continue/);
          这将在容器元素中搜索包含文本 Continue(区分大小写)的按钮。 (例如,ContinueContinue to Next 但不是continue

        【讨论】:

          【解决方案10】:

          对于那些需要查找具有特定文本的节点的人,Google 将此作为最佳结果。 通过更新,节点列表现在可以在现代浏览器中进行迭代,而无需将其转换为数组。

          解决方案可以像这样使用forEach。

          var elList = document.querySelectorAll(".some .selector");
          elList.forEach(function(el) {
              if (el.innerHTML.indexOf("needle") !== -1) {
                  // Do what you like with el
                  // The needle is case sensitive
              }
          });
          

          当普通选择器无法仅选择一个节点时,这对我在节点列表中执行查找/替换文本很有用,因此我必须逐个过滤每个节点以检查它是否有针。

          【讨论】:

            【解决方案11】:

            使用 XPath 和 document.evaluate(),并确保使用 text() 而不是 .对于 contains() 参数,否则您将匹配整个 HTML 或最外层的 div 元素。

            var headings = document.evaluate("//h1[contains(text(), 'Hello')]", document, null, XPathResult.ANY_TYPE, null );
            

            或忽略前导和尾随空格

            var headings = document.evaluate("//h1[contains(normalize-space(text()), 'Hello')]", document, null, XPathResult.ANY_TYPE, null );
            

            或匹配所有标签类型(div、h1、p等)

            var headings = document.evaluate("//*[contains(text(), 'Hello')]", document, null, XPathResult.ANY_TYPE, null );
            

            然后迭代

            let thisHeading;
            while(thisHeading = headings.iterateNext()){
                // thisHeading contains matched node
            }
            

            【讨论】:

            • 这个方法可以用来给元素添加类吗?例如thisheading.setAttribute('class', "esubject")
            • 一旦你有了元素,当然可以。但是,最好使用 element.classList.add("esubject") :)
            【解决方案12】:

            这是 XPath 方法,但使用了最少的 XPath 术语。

            基于元素属性值的常规选择(用于比较):

            // for matching <element class="foo bar baz">...</element> by 'bar'
            var things = document.querySelectorAll('[class*="bar"]');
            for (var i = 0; i < things.length; i++) {
                things[i].style.outline = '1px solid red';
            }
            

            基于元素内文本的 XPath 选择。

            // for matching <element>foo bar baz</element> by 'bar'
            var things = document.evaluate('//*[contains(text(),"bar")]',document,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null);
            for (var i = 0; i < things.snapshotLength; i++) {
                things.snapshotItem(i).style.outline = '1px solid red';
            }
            

            这里不区分大小写,因为文本更不稳定:

            // for matching <element>foo bar baz</element> by 'bar' case-insensitively
            var things = document.evaluate('//*[contains(translate(text(),"ABCDEFGHIJKLMNOPQRSTUVWXYZ","abcdefghijklmnopqrstuvwxyz"),"bar")]',document,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null);
            for (var i = 0; i < things.snapshotLength; i++) {
                things.snapshotItem(i).style.outline = '1px solid red';
            }
            

            【讨论】:

              【解决方案13】:

              我正在寻找一种使用正则表达式来做类似事情的方法,并决定构建我自己的东西,如果其他人正在寻找类似的解决方案,我想分享它。

              function getElementsByTextContent(tag, regex) {
                const results = Array.from(document.querySelectorAll(tag))
                      .reduce((acc, el) => {
                        if (el.textContent && el.textContent.match(regex) !== null) {
                          acc.push(el);
                        }
                        return acc;
                      }, []);
                return results;
              }
              

              【讨论】:

                【解决方案14】:

                我有类似的问题。

                返回所有包含 arg 文本的元素的函数。

                这对我有用:

                function getElementsByText(document, str, tag = '*') {
                return [...document.querySelectorAll(tag)]
                    .filter(
                        el => (el.text && el.text.includes(str))
                            || (el.children.length === 0 && el.outerText && el.outerText.includes(str)))
                

                }

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2019-10-08
                  • 1970-01-01
                  • 2016-06-01
                  • 1970-01-01
                  • 2021-02-07
                  • 2021-12-25
                  • 2010-12-14
                  • 2017-08-13
                  相关资源
                  最近更新 更多