Cómo obtener elemento por innerText

Respuestas:

147

Tendrás que atravesar a mano.

var aTags = document.getElementsByTagName("a");
var searchText = "SearchingText";
var found;

for (var i = 0; i < aTags.length; i++) {
  if (aTags[i].textContent == searchText) {
    found = aTags[i];
    break;
  }
}

// Use `found`.
August Lilleaas
fuente
1
@AutoSponge En realidad innerHTML es estándar. innerText no funciona en FF
AnaMaria
Actualizado el ejemplo, textContent es probablemente lo que desea en este caso. Gracias, amigos :)
August Lilleaas
1
@AugustLilleaas, ¿qué pasa con el i < il? ¿Qué está haciendo eso?
David Sawyer
1
He descubierto que si tiene <span> <span> texto de búsqueda </span> </span>, este método puede devolver el intervalo externo en lugar del interno.
Kevin Wheeler
55
No, esta pregunta es sobre JavaScript y HTML, no sobre Java
August Lilleaas
160

Podrías usar xpath para lograr esto

var xpath = "//a[text()='SearchingText']";
var matchingElement = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;

También puede buscar un elemento que contenga texto usando este xpath:

var xpath = "//a[contains(text(),'Searching')]";
carlin.scott
fuente
77
Esta debería ser la mejor respuesta. XPath puede hacer mucho más, como seleccionar nodo por valor de atributo, seleccionar conjuntos de nodos ... Introducción simple: w3schools.com/xml/xpath_syntax.asp
Timathon
1
La pregunta es, ¿cuál es la penalización de rendimiento para este truco
Vsync
2
@vsync Creo que esto será más rápido que cualquiera de las otras respuestas, ya que xpath es ejecutado por un algoritmo proporcionado por el navegador en lugar de ejecutarse en JavaScript como todas las otras respuestas aquí. Sin embargo, es una pregunta interesante.
carlin.scott
1
Parece Document.evaluate() que no se supone en el navegador IE
vsync el
1
No sé por qué, pero de alguna manera var xpath = "//a[text()='SearchingText']"; Esto no funciona, pero var xpath = "//a[contains(text(),'Searching')]"; funciona. Tenga en cuenta el carácter extraído, como \ '\'.
Joey Cho
38

Usando la sintaxis más moderna disponible en este momento, se puede hacer de manera muy limpia de esta manera:

for (const a of document.querySelectorAll("a")) {
  if (a.textContent.includes("your search term")) {
    console.log(a.textContent)
  }
}

O con un filtro separado:

[...document.querySelectorAll("a")]
   .filter(a => a.textContent.includes("your search term"))
   .forEach(a => console.log(a.textContent))

Naturalmente, los navegadores heredados no manejarán esto, pero puede usar un transpilador si se necesita soporte heredado.

usuario1106925
fuente
<3 enfoque de filtro
John Vandivier
36

Puede usar jQuery : contiene () Selector

var element = $( "a:contains('SearchingText')" );
Mouneer
fuente
Obtengo: Error: <![EX[["Tried to get element with id of \"%s\" but it is not present on the page","a:contains('SearchingText')"]]]> TAAL[1]aunque tengo elementos con "SearchingText" en ellos.
Rishabh Agrahari
15

function findByTextContent(needle, haystack, precise) {
  // needle: String, the string to be found within the elements.
  // haystack: String, a selector to be passed to document.querySelectorAll(),
  //           NodeList, Array - to be iterated over within the function:
  // precise: Boolean, true - searches for that precise string, surrounded by
  //                          word-breaks,
  //                   false - searches for the string occurring anywhere
  var elems;

  // no haystack we quit here, to avoid having to search
  // the entire document:
  if (!haystack) {
    return false;
  }
  // if haystack is a string, we pass it to document.querySelectorAll(),
  // and turn the results into an Array:
  else if ('string' == typeof haystack) {
    elems = [].slice.call(document.querySelectorAll(haystack), 0);
  }
  // if haystack has a length property, we convert it to an Array
  // (if it's already an array, this is pointless, but not harmful):
  else if (haystack.length) {
    elems = [].slice.call(haystack, 0);
  }

  // work out whether we're looking at innerText (IE), or textContent 
  // (in most other browsers)
  var textProp = 'textContent' in document ? 'textContent' : 'innerText',
    // creating a regex depending on whether we want a precise match, or not:
    reg = precise === true ? new RegExp('\\b' + needle + '\\b') : new RegExp(needle),
    // iterating over the elems array:
    found = elems.filter(function(el) {
      // returning the elements in which the text is, or includes,
      // the needle to be found:
      return reg.test(el[textProp]);
    });
  return found.length ? found : false;;
}


findByTextContent('link', document.querySelectorAll('li'), false).forEach(function(elem) {
  elem.style.fontSize = '2em';
});

findByTextContent('link3', 'a').forEach(function(elem) {
  elem.style.color = '#f90';
});
<ul>
  <li><a href="#">link1</a>
  </li>
  <li><a href="#">link2</a>
  </li>
  <li><a href="#">link3</a>
  </li>
  <li><a href="#">link4</a>
  </li>
  <li><a href="#">link5</a>
  </li>
</ul>

Por supuesto, una forma algo más simple todavía es:

var textProp = 'textContent' in document ? 'textContent' : 'innerText';

// directly converting the found 'a' elements into an Array,
// then iterating over that array with Array.prototype.forEach():
[].slice.call(document.querySelectorAll('a'), 0).forEach(function(aEl) {
  // if the text of the aEl Node contains the text 'link1':
  if (aEl[textProp].indexOf('link1') > -1) {
    // we update its style:
    aEl.style.fontSize = '2em';
    aEl.style.color = '#f90';
  }
});
<ul>
  <li><a href="#">link1</a>
  </li>
  <li><a href="#">link2</a>
  </li>
  <li><a href="#">link3</a>
  </li>
  <li><a href="#">link4</a>
  </li>
  <li><a href="#">link5</a>
  </li>
</ul>

Referencias

David dice reinstalar a Mónica
fuente
14

Enfoque funcional. Devuelve una matriz de todos los elementos coincidentes y recorta espacios alrededor durante la comprobación.

function getElementsByText(str, tag = 'a') {
  return Array.prototype.slice.call(document.getElementsByTagName(tag)).filter(el => el.textContent.trim() === str.trim());
}

Uso

getElementsByText('Text here'); // second parameter is optional tag (default "a")

si está mirando diferentes etiquetas, es decir, span o botón

getElementsByText('Text here', 'span');
getElementsByText('Text here', 'button');

El valor predeterminado tag = 'a' necesitará Babel para los navegadores antiguos

Pawel
fuente
Esto es incorrecto porque también incluye resultados para todos los nodos secundarios. Es decir, si el nodo hijo de acontendrá str- else incluirá en el getElementsByTextresultado; Cuál está mal.
avalanche1
@ avalanche1 depende si eso es indeseable. Puede ser necesario seleccionar por texto incluso si está envuelto en otra etiqueta, es decir, <span> </span>
Pawel
5

Simplemente pase su subcadena a la siguiente línea:

HTML externo

document.documentElement.outerHTML.includes('substring')

HTML interno

document.documentElement.innerHTML.includes('substring')

Puede usarlos para buscar en todo el documento y recuperar las etiquetas que contienen su término de búsqueda:

function get_elements_by_inner(word) {
    res = []
    elems = [...document.getElementsByTagName('a')];
    elems.forEach((elem) => { 
        if(elem.outerHTML.includes(word)) {
            res.push(elem)
        }
    })
    return(res)
}

Uso :

¿Cuántas veces se menciona el usuario "T3rm1" en esta página?

get_elements_by_inner("T3rm1").length

1

¿Cuántas veces se menciona jQuery?

get_elements_by_inner("jQuery").length

3

Obtenga todos los elementos que contengan la palabra "Cibernético":

get_elements_by_inner("Cybernetic")

ingrese la descripción de la imagen aquí

Cibernético
fuente
Esto devuelve verdadero o falso pero no el elemento.
T3rm1
Puede usar la condición de verdad para recorrer los elementos recuperados y obtener todo lo que necesite de esos elementos. Ver respuesta actualizada.
Cibernético el
4

El uso de la sintaxis más nueva me pareció un poco más corto en comparación con la respuesta de los demás. Así que aquí está mi propuesta:

const callback = element => element.innerHTML == 'My research'

const elements = Array.from(document.getElementsByTagName('a'))
// [a, a, a, ...]

const result = elements.filter(callback)

console.log(result)
// [a]

JSfiddle.net

Amin NAIRI
fuente
2

Para que el método de filtro del usuario1106925 funcione en <= IE11 si es necesario

Puede reemplazar el operador de propagación con:

[].slice.call(document.querySelectorAll("a"))

y el incluye llamada con a.textContent.match("your search term")

que funciona bastante bien:

[].slice.call(document.querySelectorAll("a"))
   .filter(a => a.textContent.match("your search term"))
   .forEach(a => console.log(a.textContent))
Alkie
fuente
Me gusta este metodo También puedes en Array.fromlugar de [].slice.call. Por ejemplo: Array.from(document.querySelectorAll('a'))
Richard
1

Si bien es posible pasar por el texto interno, creo que se dirige hacia el camino equivocado. ¿Esa cadena interna se genera dinámicamente? Si es así, puede asignar una clase a la etiqueta o, mejor aún, una identificación cuando el texto ingrese allí. Si es estático, entonces es aún más fácil.

Zack Marrapese
fuente
1

Puede usar a TreeWalkerpara repasar los nodos DOM y localizar todos los nodos de texto que contienen el texto, y devolver sus padres:

const findNodeByContent = (text, root = document.body) => {
  const treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);

  const nodeList = [];

  while (treeWalker.nextNode()) {
    const node = treeWalker.currentNode;

    if (node.nodeType === Node.TEXT_NODE && node.textContent.includes(text)) {
      nodeList.push(node.parentNode);
    }
  };

  return nodeList;
}

const result = findNodeByContent('SearchingText');

console.log(result);
<a ...>SearchingText</a>

Ori Drori
fuente
1

Esto hace el trabajo.
Devuelve una matriz de nodos que contiene text.

function get_nodes_containing_text(selector, text) {
    const elements = [...document.querySelectorAll(selector)];

    return elements.filter(
      (element) =>
        element.childNodes[0]
        && element.childNodes[0].nodeValue
        && RegExp(text, "u").test(element.childNodes[0].nodeValue.trim())
    );
  }
avalancha1
fuente
0

Creo que necesitarás ser un poco más específico para que podamos ayudarte.

  1. ¿Cómo estás encontrando esto? Javascript? PHP? Perl?
  2. ¿Se puede aplicar un atributo de identificación a la etiqueta?

Si el texto es único (o realmente, si no lo es, pero tendría que ejecutar una matriz), puede ejecutar una expresión regular para encontrarlo. El uso de preg_match () de PHP funcionaría para eso.

Si está usando Javascript y puede insertar un atributo ID, puede usar getElementById ('id'). Luego puede acceder a los atributos del elemento devuelto a través del DOM: https://developer.mozilla.org/en/DOM/element.1 .

Jeff Meyers
fuente
0

Solo necesitaba una forma de obtener el elemento que contiene un texto específico y esto es lo que se me ocurrió.

Úselo document.getElementsByInnerText()para obtener múltiples elementos (múltiples elementos pueden tener el mismo texto exacto), y utilícelo document.getElementByInnerText()para obtener solo un elemento (primera coincidencia).

Además, puede localizar la búsqueda utilizando un elemento (por ejemplo someElement.getElementByInnerText()) en lugar de document.

Es posible que deba ajustarlo para que sea cruzado o satisfaga sus necesidades.

Creo que el código se explica por sí mismo, así que lo dejaré como está.

HTMLElement.prototype.getElementsByInnerText = function (text, escape) {
    var nodes  = this.querySelectorAll("*");
    var matches = [];
    for (var i = 0; i < nodes.length; i++) {
        if (nodes[i].innerText == text) {
            matches.push(nodes[i]);
        }
    }
    if (escape) {
        return matches;
    }
    var result = [];
    for (var i = 0; i < matches.length; i++) {
        var filter = matches[i].getElementsByInnerText(text, true);
        if (filter.length == 0) {
            result.push(matches[i]);
        }
    }
    return result;
};
document.getElementsByInnerText = HTMLElement.prototype.getElementsByInnerText;

HTMLElement.prototype.getElementByInnerText = function (text) {
    var result = this.getElementsByInnerText(text);
    if (result.length == 0) return null;
    return result[0];
}
document.getElementByInnerText = HTMLElement.prototype.getElementByInnerText;

console.log(document.getElementsByInnerText("Text1"));
console.log(document.getElementsByInnerText("Text2"));
console.log(document.getElementsByInnerText("Text4"));
console.log(document.getElementsByInnerText("Text6"));

console.log(document.getElementByInnerText("Text1"));
console.log(document.getElementByInnerText("Text2"));
console.log(document.getElementByInnerText("Text4"));
console.log(document.getElementByInnerText("Text6"));
<table>
    <tr>
        <td>Text1</td>
    </tr>
    <tr>
        <td>Text2</td>
    </tr>
    <tr>
        <td>
            <a href="#">Text2</a>
        </td>
    </tr>
    <tr>
        <td>
            <a href="#"><span>Text3</span></a>
        </td>
    </tr>
    <tr>
        <td>
            <a href="#">Special <span>Text4</span></a>
        </td>
    </tr>
    <tr>
        <td>
            Text5
            <a href="#">Text6</a>
            Text7
        </td>
    </tr>
</table>

akinuri
fuente