Javascript .querySelector 通过 innerTEXT 查找 <div>
Javascript .querySelector find <div> by innerTEXT
如何找到带有特定文本的 DIV?例如:
<div>
SomeText, text continues.
</div>
尝试使用这样的东西:
var text = document.querySelector('div[SomeText*]').innerTEXT;
alert(text);
当然不行。我该怎么做?
既然你在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 的父元素具有 id
的 container
。您通常可以直接从 id 访问容器,但让我们以正确的方式进行。
var conty = document.getElementById("container"),
divs = conty.querySelectorAll("div"),
myDiv = [...divs].filter(e => e.innerText == "SomeText");
就是这样。
OP 的问题是关于 JavaScript 而不是 jQuery。
虽然有很多答案而且我喜欢@Pawan Nogariya ,但请检查这个替代方案。
您可以在 JavaScript 中使用 XPATH。有关 MDN 文章 here.
的更多信息
document.evaluate()
方法计算 XPATH query/expression。因此,您可以在那里传递 XPATH 表达式,遍历 HTML 文档并找到所需的元素。
在 XPATH 中,您可以通过如下文本节点 select 一个元素,从而获得具有以下文本节点的 div
。
//div[text()="Hello World"]
要获取包含一些文本的元素,请使用以下命令:
//div[contains(., 'Hello')]
XPATH 中的 contains()
方法将节点作为第一个参数,将要搜索的文本作为第二个参数。
检查这个 plunk here,这是在 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 本身,这会抓取包含您要查找的文本的文本节点的父节点。
您可以使用这个非常简单的解决方案:
Array.from(document.querySelectorAll('div'))
.find(el => el.textContent === 'SomeText, text continues.');
Array.from
会将 NodeList 转换为数组(有多种方法可以做到这一点,例如展开运算符或切片)
结果现在是一个数组,允许使用 Array.find
方法,然后您可以放入任何谓词。您还可以使用正则表达式或任何您喜欢的方式检查 textContent。
注意 Array.from
和 Array.find
是 ES2015 特性。无需转译器即可与 IE10 等较旧的浏览器兼容:
Array.prototype.slice.call(document.querySelectorAll('div'))
.filter(function (el) {
return el.textContent === 'SomeText, text continues.'
})[0];
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
}
});
当普通选择器不能只选择一个节点时,这对我在节点列表中做一个 find/replace 文本很有用,所以我不得不一个接一个地过滤每个节点以检查它的针。
使用 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展开运算符将所有div
的NodeList转为数组
如果 div
包含 查询字符串,则提供输出,而不仅仅是 等于 查询字符串(这发生在其他一些答案中)。例如它不仅应该为 'SomeText' 提供输出,还应该为 'SomeText, text continues'.
提供输出
输出整个 div
内容,而不仅仅是查询字符串。例如对于 'SomeText, text continues' 它应该输出整个字符串,而不仅仅是 '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';
}
我有类似的问题。
return 包含来自 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 select 或 select 你的元素,就像 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 select或稍微提高性能。
这里已经有很多很棒的解决方案。然而,为了提供一个更精简的解决方案,并与 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 class 和 go 的所有 divs ] innerText(例如向左走或向下或向右走或这是Good)
document.queryInnerText('div.link', 'go');
这将与上面的示例完全一样,除了它 return 只有第一个匹配元素。
document.queryInnerTextAll('a', /^Next$/);
查找所有具有确切文本 Next(区分大小写)的 link。这将排除包含单词 Next 以及其他文本的 link。
document.queryInnerText('a', /next/i);
查找包含单词 next 的第一个 link,不区分大小写(例如 Next Page 或 Go to下一个)
e = document.querySelector('#page');
e.queryInnerText('button', /Continue/);
这会在容器元素中搜索包含文本 Continue(区分大小写)的按钮。 (例如 Continue 或 Continue to Next 但不是 continue)
在 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;
};
}
我一直在寻找一种使用正则表达式做类似事情的方法,并决定构建我自己的东西,如果其他人正在寻找类似的解决方案,我想分享它。
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;
}
如何找到带有特定文本的 DIV?例如:
<div>
SomeText, text continues.
</div>
尝试使用这样的东西:
var text = document.querySelector('div[SomeText*]').innerTEXT;
alert(text);
当然不行。我该怎么做?
既然你在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 的父元素具有 id
的 container
。您通常可以直接从 id 访问容器,但让我们以正确的方式进行。
var conty = document.getElementById("container"),
divs = conty.querySelectorAll("div"),
myDiv = [...divs].filter(e => e.innerText == "SomeText");
就是这样。
OP 的问题是关于 JavaScript 而不是 jQuery。
虽然有很多答案而且我喜欢@Pawan Nogariya
您可以在 JavaScript 中使用 XPATH。有关 MDN 文章 here.
的更多信息document.evaluate()
方法计算 XPATH query/expression。因此,您可以在那里传递 XPATH 表达式,遍历 HTML 文档并找到所需的元素。
在 XPATH 中,您可以通过如下文本节点 select 一个元素,从而获得具有以下文本节点的 div
。
//div[text()="Hello World"]
要获取包含一些文本的元素,请使用以下命令:
//div[contains(., 'Hello')]
XPATH 中的 contains()
方法将节点作为第一个参数,将要搜索的文本作为第二个参数。
检查这个 plunk here,这是在 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 本身,这会抓取包含您要查找的文本的文本节点的父节点。
您可以使用这个非常简单的解决方案:
Array.from(document.querySelectorAll('div'))
.find(el => el.textContent === 'SomeText, text continues.');
Array.from
会将 NodeList 转换为数组(有多种方法可以做到这一点,例如展开运算符或切片)结果现在是一个数组,允许使用
Array.find
方法,然后您可以放入任何谓词。您还可以使用正则表达式或任何您喜欢的方式检查 textContent。
注意 Array.from
和 Array.find
是 ES2015 特性。无需转译器即可与 IE10 等较旧的浏览器兼容:
Array.prototype.slice.call(document.querySelectorAll('div'))
.filter(function (el) {
return el.textContent === 'SomeText, text continues.'
})[0];
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
}
});
当普通选择器不能只选择一个节点时,这对我在节点列表中做一个 find/replace 文本很有用,所以我不得不一个接一个地过滤每个节点以检查它的针。
使用 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展开运算符将所有
div
的NodeList转为数组如果
div
包含 查询字符串,则提供输出,而不仅仅是 等于 查询字符串(这发生在其他一些答案中)。例如它不仅应该为 'SomeText' 提供输出,还应该为 'SomeText, text continues'. 提供输出
输出整个
div
内容,而不仅仅是查询字符串。例如对于 'SomeText, text continues' 它应该输出整个字符串,而不仅仅是 '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';
}
我有类似的问题。
return 包含来自 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 select 或 select 你的元素,就像 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 select或稍微提高性能。
这里已经有很多很棒的解决方案。然而,为了提供一个更精简的解决方案,并与 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 class 和 go 的所有 divs ] innerText(例如向左走或向下或向右走或这是Good)document.queryInnerText('div.link', 'go');
这将与上面的示例完全一样,除了它 return 只有第一个匹配元素。document.queryInnerTextAll('a', /^Next$/);
查找所有具有确切文本 Next(区分大小写)的 link。这将排除包含单词 Next 以及其他文本的 link。document.queryInnerText('a', /next/i);
查找包含单词 next 的第一个 link,不区分大小写(例如 Next Page 或 Go to下一个)e = document.querySelector('#page');
e.queryInnerText('button', /Continue/);
这会在容器元素中搜索包含文本 Continue(区分大小写)的按钮。 (例如 Continue 或 Continue to Next 但不是 continue)
在 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;
};
}
我一直在寻找一种使用正则表达式做类似事情的方法,并决定构建我自己的东西,如果其他人正在寻找类似的解决方案,我想分享它。
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;
}