Javascript .querySelector通过innerTEXT查找<div>


108

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

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

尝试使用这样的东西:

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

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


即使您可以做到,它也不会比获得所有div并通过innerText属性过滤它们要快得多。那么,为什么不手动进行呢?
Redu

Answers:


100

OP的问题是关于普通JavaScript而不是jQuery的。尽管答案很多,而且我喜欢@Pawan Nogariya 答案,请检查此替代方法。

您可以在JavaScript中使用XPATH。有关MDN文章的更多信息,请点击此处

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

在XPATH中,您可以通过文本节点选择一个元素,如下所示,该元素将获得div具有以下文本节点的元素。

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

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

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

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

在这里检查这个问题,这是在JavaScript中使用XPATH的示例

这是一个代码片段:

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(。,\'/您登录(。*)乘此会话/ \')]',然后警报(thisHeading.textContent。$ 1)
passwd

好的,我这样做:alert(thisHeading.textContent.replace(/.*You have login (.*) times.*/,'$1')) ;
passwd

@passwd,好吧,你不能这样做。XPATH 1.0(.evaluate()使用。不支持Regex 。如果我错了,请纠正我),因此,首先,您无法搜索与正则表达式匹配的内容。其次,.textContent属性返回元素的文本节点。如果您想从文本中获取一个值,则应该通过创建某种与正则表达式匹配并返回group中匹配值的函数来显式地处理它,为此请在单独的线程上提出一个新问题。
痢疾

Internet Explorer:不支持。但在Edge中受支持。我不确定这意味着什么,从版本角度来看。
罗尔夫(Rolf)

万一我要查找的元素丢失,应该如何处理错误?
nenito

72

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

Array.from(document.querySelectorAll('div'))
  .find(el => el.textContent === 'SomeText, text continues.');
  1. Array.from将节点列表转换为数组(有多种方法来做到这一点,如传播经营者或切片)

  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];

2
如果要查找多个元素,请替换findfilter
RubbelDieKatz

38

由于您已经在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

1
看起来像这样有效,但是作为回报,我只能得到:[object HTMLDivElement],[object HTMLDivElement]
passwd

是的,您将获得包含匹配文本的div,然后您可以在其中调用类似这样的内部文本方法foundDivs[0].innerText,就这么简单
Pawan Nogariya,2016年

20

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

  • 使用ES6扩展运算符将all div的NodeList转换为数组。

  • 如果div 包含查询字符串,则提供输出,而不仅是与查询字符串完全相等(在某些其他答案中会发生)一样。例如,它不仅应为“ SomeText”提供输出,而且还应为“ SomeText,文本继续”提供输出。

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

  • 允许多个div包含字符串,而不仅仅是单个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>


3
我喜欢这个。整洁,简洁和易于理解-同时进行。
ba_ul

2
肯定会效率低下吗?想想innerHTML您的最顶端的<div>s有多大。您应该先过滤掉div包含子级的。还怀疑document.getElementsByTagName('div')可能更快,但我会确定基准。
Timmmm

这对我来说很棒,我一开始可以设置一个好的选择器,因为我已经知道它只能放在桌子上,很酷,谢谢
gsalgadotoledo

10

最好查看您是否有要查询的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
Chase Sandmann

5

如果您不想使用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的父级。


3

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

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选择器的性能。


2

对于需要查找带有特定文本的节点的用户来说,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
    }
});

当普通选择器不能只选择一个节点时,这对我来说可以在节点列表中查找/替换文本,因此我不得不逐个过滤每个节点以检查针头。


2

使用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")
马修(Matthew)

确定元素后,请确定。但是,最好使用element.classList.add(“ esubject”):)
史蒂文·斯潘金

1

这是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';
}

0

我有类似的问题。

返回所有包含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)))

}


0

这里已经有很多很棒的解决方案。但是,为了提供一种更简化的解决方案,以及一个与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');
    这将找到所有的div在innerText中包含带有单词go链接类的(例如,向左向下向右It's Go od
  • document.queryInnerText('div.link', 'go');
    除仅返回第一个匹配元素外,这将与上面的示例完全一样。
  • document.queryInnerTextAll('a', /^Next$/);
    查找所有带有确切文本下一步(区分大小写)的链接。这将排除包含单词Next和其他文本的链接。
  • document.queryInnerText('a', /next/i);
    不管大小写如何,都 找到包含单词next的第一个链接(例如,Next PageGo to next
  • e = document.querySelector('#page');
    e.queryInnerText('button', /Continue/);
    这将在容器元素内搜索包含文本“ 继续”(区分大小写)的按钮。(例如,继续继续到下一个,但不继续
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.