JavaScript中使用.querySelector查找包含特定文本的<div>标签

248
如何找到包含特定文本的DIV?例如:
<div>
SomeText, text continues.
</div>

尝试使用类似这样的东西:

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

但当然这不会起作用。我该怎么做?


即使你能做到,它也不会比获取所有div并通过innerText属性进行过滤更快。那么为什么不手动操作呢? - Redu
14个回答

2
这里有一种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';
}

2

由于数据属性中的文字长度没有限制,可以使用数据属性!然后您可以使用常规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选择器的范围以提高性能。

1
不会删除。在我看来,这是唯一一个完全按照问题要求并允许使用实际 CSS 选择器查找文本的答案。它是唯一一个可以将选择器放入实际的 CSS 文件中,例如 *[data-my-inner-text='Different text.'],同时还允许使用原生的 querySelector。虽然可能会增加内存中文档的“大小”,但由于浏览器引擎优化 DOM 查询的方式,实际查询应该是最快的。 - keymap
OP并没有要求CSS选择器。他要求的是:“Javascript .querySelector通过innerTEXT查找<div>”,但没有指定CSS选择器是必需的。增加页面大小对于Google排名不利,对于速度优化也不利,并且添加数据会打开潜在的错误风险,例如引号/特殊字符可能会破坏HTML等。本帖中的其他答案已经实现了OP的请求,即查找包含任何文本的DIV。这就是为什么你会得到负分的原因。你可以保留你的答案,但我预计会因为低效的答案、不需要的副作用和风险而得到负分。 - OG Sean
1
我猜这取决于你如何解释OP的问题。Document.querySelector()只接受有效的CSS选择器作为参数,因此从字面上讲,我的答案是唯一允许您使用querySelector通过innerText查找元素的答案。所有其他答案都涉及创建某些包装函数来围绕querySelector,而不是直接使用单个调用querySelector。 "增加页面大小" - 我的方法显然不会增加下载的HTML大小,而只会在内存中增加页面大小,在Google排名上应该没有任何影响。 - keymap
1
此外,“不利于速度优化” - 真正取决于页面结构以及如何应用此解决方案。使用我的方法,实际查询将比这里的任何其他方法都要*快。但是,初始页面处理/渲染速度可能会变慢。这更多是一个问题,你想在哪里减速 - 在初始页面加载时还是在查询期间。如果您正在进行大量查询,则存在一种情况,我的方法将是更优秀的选择... - keymap
使用这种“修补”方法,我不需要更改依赖于CSS选择器的其他脚本(在我的情况下是ActionClick)。我只需为某些项目触发一个修补命令ActionPatch,然后就可以使用它了 :) 请参阅https://github.com/muescha/dot_hammerspoon/commit/f4e969e14d7eec369fca39e12dc6a3793a8f04ca和https://github.com/muescha/dot_hammerspoon/commit/c73a244ff228bba625b134ca1f07651a0738b36e。 - undefined
显示剩余3条评论

2

这里已经有很多优秀的解决方案了。然而,为了提供一个更加简洁的方案,并符合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');
    这将查找所有包含链接类且innerText中包含单词godivs(例如Go LeftGO downgo rightIt's Good
  • 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

1
我遇到了类似的问题。
返回所有包含参数文本的元素的函数。
这对我有效:
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)))

}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接