How can I find elements by text content with jQuery?
Can anyone tell me if it's possible to find an element based开发者_C百科 on its content rather than by an ID or class?
I am attempting to find elements that don't have distinct classes or IDs. (Then I then need to find that element's parent.)
You can use the :contains
selector to get elements based on their content.
Demo here
$('div:contains("test")').css('background-color', 'red');
<div>This is a test</div>
<div>Another Div</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
In jQuery documentation it says:
The matching text can appear directly within the selected element, in any of that element's descendants, or a combination
Therefore it is not enough that you use :contains()
selector, you also need to check if the text you search for is the direct content of the element you are targeting for, something like that:
function findElementByText(text) {
var jSpot = $("b:contains(" + text + ")")
.filter(function() { return $(this).children().length === 0;})
.parent(); // because you asked the parent of that element
return jSpot;
}
Fellas, I know this is old but hey I've this solution which I think works better than all. First and foremost overcomes the Case Sensitivity that the jquery :contains() is shipped with:
var text = "text";
var search = $( "ul li label" ).filter( function ()
{
return $( this ).text().toLowerCase().indexOf( text.toLowerCase() ) >= 0;
}).first(); // Returns the first element that matches the text. You can return the last one with .last()
Hope someone in the near future finds it helpful.
Rocket's answer doesn't work.
<div>hhhhhh
<div>This is a test</div>
<div>Another Div</div>
</div>
I simply modified his DEMO here and you can see the root DOM is selected.
$('div:contains("test"):last').css('background-color', 'red');
add ":last" selector in the code to fix this.
The following jQuery selects div nodes that contain text but have no children, which are the leaf nodes of the DOM tree.
$('div:contains("test"):not(:has(*))').css('background-color', 'red');
<div>div1
<div>This is a test, nested in div1</div>
<div>Nested in div1<div>
</div>
<div>div2 test
<div>This is another test, nested in div2</div>
<div>Nested in div2</div>
</div>
<div>
div3
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
Best way in my opinion.
$.fn.findByContentText = function (text) {
return $(this).contents().filter(function () {
return $(this).text().trim() == text.trim();
});
};
Yes, use the jQuery contains
selector.
All answers so far do not match all specific elements containing a direct child text node which contains a specific text.
Consider the following example. We want to find all hobbits, that is, all div
s containing a direct child text node, which contains the word "hobbit" (including word borders, ignoring the case).
$(function() {
const ELEMTYPE = Node.ELEMENT_NODE
const TEXTTYPE = Node.TEXT_NODE
/*
Behaves a bit like Python's os.walk().
The `topdown` parameter is not strictly necessary for this example.
*/
function* walk_text(root, topdown=true) {
const childs = []
const textchilds = []
for (const child of root.childNodes) {
const childtype = child.nodeType
if (childtype === ELEMTYPE) {
childs.push(child)
} else if (childtype === TEXTTYPE) {
textchilds.push(child)
}
}
if (topdown) {
yield [root, textchilds]
}
for (const child of childs) {
yield* walk_text(child, topdown)
}
if (!topdown) {
yield [root, textchilds]
}
}
function* walk_matching(startnode, nodepat, textpat) {
for ( [elem, textchilds] of walk_text(startnode) ) {
if ( nodepat.test(elem.nodeName) ) {
for ( const textchild of textchilds ) {
if ( textpat.test(textchild.nodeValue) ) {
yield elem
break
}
}
}
}
}
// raw dom node
let startnode = $('body')[0]
// search for element nodes with names matching this pattern ...
let nodepat = /^div$/i
// ... containing direct child text nodes matching this pattern
let textpat = /\bhobbit\b/i
for ( const node of walk_matching( startnode, nodepat, textpat ) ) {
$(node).css({
border: '1px solid black',
color: 'black'
})
}
});
div {
margin:10px 0;
padding: 10px;
border: 1px solid silver;
color: silver;
font-style:italic;
}
div:before {
display:block;
content: attr(name);
font-style:normal;
}
/* Inserted by SO, we are not interested in it */
body + div {
display: none;
}
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>Find the hobbits</title>
</head>
<body>
<div name='Tolkien'>
book writer
<div name='Elrond'>
elven king
<div name='Arwen'>elven princess</div>
<div name='Aragorn'>human king, son-in-law</div>
</div>
<div name='Gandalf'>
wizard, expert for hobbits
<div name='Bilbo'>
old hobbit
<div name='Frodo'>
young hobbit
<div name='Samweis'>best friend hobbit</div>
</div>
</div>
<div name='Gollum'>ex hobbit</div>
<div name='Odo'>hobbit</div>
</div>
</div>
<script src= "https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
</body>
</html>
The other answers find (when searching for 'hobbit'):
- Rocket Hazmat's answer: Tolkien, Gandalf, Bilbo, Frodo, Samweis, Gollum, Odo
- Morgs's answer: Tolkien
- yoav barnea's answer: Gandalf, Frodo
- Nicholas Sushkin's answer: Samweis, Gollum, Odo
- Rocket Hazmat's answer in the comments, Terry Lin's answer, rplaurindo's answer: Odo
All of these answers make sense, depending on what you want to do. Choose wise, because Rocket Hazmat's answers, Morgs's answer and Terry Lin's answer partially perform more than two times faster than my solution. I guess that is because they don't need to walk through the whole DOM. Most answers who use .filter()
perform very fast.
精彩评论