¿Cómo puedo encontrar DIV con cierto texto? Por ejemplo:

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

Intentando usar algo como esto:

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

Pero, por supuesto, no funcionará. ¿Cómo puedo hacerlo?

122
passwd 8 may. 2016 a las 12:41

11 respuestas

La mejor respuesta

La pregunta de OP es sobre JavaScript y no jQuery . Aunque hay muchas respuestas y me gusta @Pawan Nogariya respuesta, compruebe esta alternativa.

Puede usar XPATH en JavaScript. Más información sobre el artículo de MDN aquí.

El método document.evaluate() evalúa una consulta / expresión XPATH. Entonces puede pasar expresiones XPATH allí, atravesar el documento HTML y ubicar el elemento deseado.

En XPATH puede seleccionar un elemento, por el nodo de texto como el siguiente, que obtiene el div que tiene el siguiente nodo de texto.

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

Para obtener un elemento que contiene texto, use lo siguiente:

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

El método contains() en XPATH toma un nodo como primer parámetro y el texto para buscar como segundo parámetro.

Compruebe este plunk aquí, este es un ejemplo de uso de XPATH en JavaScript

Aquí hay un fragmento de código:

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

Como puede ver, puedo tomar el elemento HTML y modificarlo a mi gusto.

84
wyu 19 ene. 2020 a las 09:29

Use XPath y document.evaluate (), y asegúrese de usar text () y no. para el argumento contiene (), o de lo contrario tendrá todo el HTML, o el elemento div más externo emparejado.

var headings = document.evaluate("//h1[contains(text(), 'Hello')]", document, null, XPathResult.ANY_TYPE, null );

O ignorar espacios en blanco iniciales y finales

var headings = document.evaluate("//h1[contains(normalize-space(text()), 'Hello')]", document, null, XPathResult.ANY_TYPE, null );

O hacer coincidir todos los tipos de etiquetas (div, h1, p, etc.)

var headings = document.evaluate("//*[contains(text(), 'Hello')]", document, null, XPathResult.ANY_TYPE, null );

Luego iterar

let thisHeading;
while(thisHeading = headings.iterateNext()){
    // thisHeading contains matched node
}
1
Steven Spungin 11 dic. 2017 a las 15:54

Aquí está el enfoque XPath pero con un mínimo de jerga XPath.

Selección regular basada en valores de atributo de elemento (para comparación):

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

Selección de XPath basada en el texto dentro del elemento.

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

Y aquí hay mayúsculas y minúsculas ya que el texto es más volátil:

// 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
Jan Kyu Peblik 22 ago. 2019 a las 22:34

Podrías usar esta solución bastante simple:

Array.from(document.querySelectorAll('div'))
  .find(el => el.textContent === 'SomeText, text continues.');
  1. Array.from convertirá la NodeList en una matriz (existen varios métodos para hacer esto, como el operador de propagación o el segmento)

  2. El resultado ahora es una matriz que permite usar el método Array.find, luego puedes poner cualquier predicado. También puede verificar el contenido del texto con una expresión regular o lo que quiera.

Tenga en cuenta que Array.from y Array.find son características de ES2015. Ser compatible con navegadores antiguos como IE10 sin un transpiler:

Array.prototype.slice.call(document.querySelectorAll('div'))
  .filter(function (el) {
    return el.textContent === 'SomeText, text continues.'
  })[0];
50
Niels 17 dic. 2017 a las 08:30

Como no hay límites para la longitud del texto en un atributo de datos, ¡use atributos de datos! Y luego puede usar selectores CSS regulares para seleccionar sus elementos como lo desea el 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>

Idealmente, debe hacer la parte de configuración del atributo de datos en la carga del documento y reducir un poco el selector querySelectorAll para el rendimiento.

0
keymap 25 feb. 2020 a las 22:58

Si no quieres usar jquery o algo así, puedes intentar esto:

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

Una vez que tenga los nodos en una matriz que contiene el texto, puede hacer algo con ellos. Como alertar a cada uno o imprimir en la consola. Una advertencia es que esto puede no necesariamente tomar divs per se, esto tomará el padre del nodo de texto que tiene el texto que está buscando.

3
Steve Botello 8 may. 2016 a las 10:37

Lo mejor es ver si tiene un elemento padre del div que está consultando. Si es así, obtenga el elemento padre y realice un element.querySelectorAll("div"). Una vez que obtenga nodeList aplique un filtro sobre la propiedad innerText. Suponga que un elemento padre del div que estamos consultando tiene un id de container. Normalmente puede acceder al contenedor directamente desde la identificación, pero hagámoslo de la manera correcta.

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

Eso es todo.

8
Redu 8 may. 2016 a las 09:53

Esta solución hace lo siguiente:

  • Utiliza el operador de propagación ES6 para convertir la NodeList de todos los div s en una matriz.

  • Proporciona resultados si div contiene la cadena de consulta, no solo si es exactamente igual a la cadena de consulta (lo que sucede para algunas de las otras respuestas). p.ej. Debe proporcionar resultados no solo para 'SomeText' sino también para 'SomeText, text text'.

  • Emite todo el contenido de div, no solo la cadena de consulta. p.ej. Para 'SomeText, el texto continúa', debería generar esa cadena completa, no solo 'SomeText'.

  • Permite que múltiples div s contengan la cadena, no solo un 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>
17
Andrew Willems 12 abr. 2018 a las 12:51

Como lo ha pedido en JavaScript, puede tener algo como esto

function contains(selector, text) {
  var elements = document.querySelectorAll(selector);
  return Array.prototype.filter.call(elements, function(element){
    return RegExp(text).test(element.textContent);
  });
}

Y luego llámalo así

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
35
Pawan Nogariya 8 may. 2016 a las 09:52

Google tiene esto como un resultado superior para Para aquellos que necesitan encontrar un nodo con cierto texto. A modo de actualización, una lista de nodos ahora es iterable en los navegadores modernos sin tener que convertirla en una matriz.

La solución se puede usar para cada una de ellas.

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

Esto me funcionó para hacer un texto de búsqueda / reemplazo dentro de una lista de nodos cuando un selector normal no podía elegir solo un nodo, por lo que tuve que filtrar cada nodo uno por uno para verificar si la aguja.

1
Vigilante 6 nov. 2017 a las 22:59

Tuve un problema similar

Función que devuelve todos los elementos que incluyen texto de arg.

Esto funciona para mí:

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
Paweł Zieliński 27 oct. 2019 a las 21:00