Javascript .querySelector查找<由innerTEXT

我如何能找到DIV与某些文本?例如:

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

试图使用这样的东西:

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

当然,这是行不通的。我该怎么做呢?

283975 次浏览

因为你已经在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

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

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

就是这样。

OP的问题是关于普通的JavaScript而不是jQuery。 虽然有很多答案,我喜欢@Pawan Nogariya 回答,请检查这个替代方案

你可以在JavaScript中使用XPATH。有关MDN文章在这里的更多信息。

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

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

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

要获得一个包含一些文本的元素,使用以下方法:

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

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

检查这个在这里,这是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元素并按我喜欢的方式修改它。

如果你不想使用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的父节点。

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

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

谷歌有这个作为顶部结果为那些谁需要找到一个节点与特定的文本。 通过更新,节点列表现在在现代浏览器中是可迭代的,而不必将其转换为数组

解决方案可以像这样使用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
}
});

当一个普通的选择器不能选择一个节点时,我可以在节点列表中查找/替换文本,所以我必须一个接一个地过滤每个节点以检查它是否有针。

使用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
}

该解决方案实现如下功能:

  • 使用ES6展开操作符将所有__abc的NodeList转换为数组。

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

  • 输出整个div内容,而不仅仅是查询字符串。例如,对于'SomeText, text continue ',它应该输出整个字符串,而不仅仅是'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>

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

我也有类似的问题。

函数返回包含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)))

由于数据属性中的文本长度没有限制,所以请使用数据属性!然后你可以使用常规的css选择器来选择你的元素(s)像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选择器的范围以提高性能。

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

简单地实现以下函数:

// 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');
    这将在innerText中找到所有包含链接类的div(例如)。往左 or 往下走 or 去对吧 or 这是< em > < / em > od) <李> document.queryInnerText('div.link', 'go');
    这将与上面的例子完全相同,除了它只返回第一个匹配的元素 <李> document.queryInnerTextAll('a', /^Next$/);
    找到所有带有确切文本下一个的链接(区分大小写)。这将排除包含单词下一个和其他文本的链接 <李> document.queryInnerText('a', /next/i);
    找到第一个包含单词下一个的链接,无论大小写(例如。下一个页面 or 转下一节) <李> e = document.querySelector('#page');
    e.queryInnerText('button', /Continue/);
    它在容器元素中搜索包含文本继续(区分大小写)的按钮。(如。继续继续下一节但不是继续)

在2021年遇到这个问题时,我发现使用XPATH太复杂了(需要学习其他东西),不适合做一些应该相当简单的事情。

我想到了这个:

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

用法:

querySelectorIncludesText('button', 'Send')

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

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

  /**
* 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;
};
}

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

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