Comment obtenir un élément par innerText

Réponses:

148

Vous devrez traverser à la main.

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
la source
1
@AutoSponge En fait, innerHTML est standard. innerText ne fonctionne pas dans FF
AnaMaria
Mise à jour de l'exemple, textContent est probablement ce que vous voulez dans ce cas. Thanks, folks :)
August Lilleaas
1
@AugustLilleaas, qu'est-ce qui se passe avec le i < il? Qu'est-ce que ça fait?
David Sawyer
1
J'ai constaté que si vous disposez d'un <span> <span> texte de recherche </span> </span>, cette méthode peut renvoyer l'intervalle externe au lieu de l'interne.
Kevin Wheeler
5
Non, cette question concerne JavaScript et HTML, pas Java
August Lilleaas
160

Vous pouvez utiliser xpath pour accomplir cela

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

Vous pouvez également rechercher un élément contenant du texte en utilisant ce xpath:

var xpath = "//a[contains(text(),'Searching')]";
carlin.scott
la source
7
Cela devrait être la meilleure réponse. XPath peut faire beaucoup plus, comme sélectionner un nœud par valeur d'attribut, sélectionner des ensembles de nœuds ... Introduction simple: w3schools.com/xml/xpath_syntax.asp
Timathon
1
La question est, quelle est la pénalité de performance pour cette supercherie
vsync
2
@vsync Je pense que ce sera plus rapide que toutes les autres réponses car le xpath est exécuté par un algorithme fourni par le navigateur plutôt que de s'exécuter en javascript comme toutes les autres réponses ici. C'est une question intéressante cependant.
carlin.scott
1
Semble Document.evaluate() n'est pas censé dans le navigateur IE
vsync
1
Je ne sais pas pourquoi, mais d'une manière ou d'une autre, var xpath = "//a[text()='SearchingText']"; cela ne fonctionne pas, mais var xpath = "//a[contains(text(),'Searching')]"; cela fonctionne. Soyez conscient du caractère excapé, tel que \ '\'.
Joey Cho
38

En utilisant la syntaxe la plus moderne disponible pour le moment, cela peut être fait très proprement comme ceci:

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

Ou avec un filtre séparé:

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

Naturellement, les navigateurs hérités ne gèrent pas cela, mais vous pouvez utiliser un transpilateur si un support hérité est nécessaire.

user1106925
la source
<3 approche de filtrage
John Vandivier
36

Vous pouvez utiliser jQuery : contains () Selector

var element = $( "a:contains('SearchingText')" );
Mouneer
la source
J'obtiens: Error: <![EX[["Tried to get element with id of \"%s\" but it is not present on the page","a:contains('SearchingText')"]]]> TAAL[1]bien que j'ai des éléments avec "SearchingText" en eux.
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>

Bien sûr, un moyen un peu plus simple est toujours:

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>

Références:

David dit de réintégrer Monica
la source
14

Approche fonctionnelle. Renvoie le tableau de tous les éléments correspondants et ajuste les espaces lors de la vérification.

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

Usage

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

si vous regardez à travers différentes balises, par exemple span ou bouton

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

La valeur par défaut tag = 'a' aura besoin de Babel pour les anciens navigateurs

Pawel
la source
Ceci est incorrect car il inclut également les résultats pour tous les nœuds enfants. Ie si le nœud enfant de acontiendra str- elsera inclus dans le getElementsByTextrésultat; ce qui est faux.
avalanche1
@ avalanche1 cela dépend si c'est indésirable. Il peut être nécessaire de sélectionner par texte même s'il est enveloppé dans une autre balise, par exemple <span> </span>
Pawel
5

Passez simplement votre sous - chaîne dans la ligne suivante:

HTML externe

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

HTML interne

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

Vous pouvez les utiliser pour rechercher dans tout le document et récupérer les balises contenant votre terme de recherche:

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

Utilisation :

Combien de fois l'utilisateur "T3rm1" est-il mentionné sur cette page?

get_elements_by_inner("T3rm1").length

1

Combien de fois jQuery est-il mentionné?

get_elements_by_inner("jQuery").length

3

Récupère tous les éléments contenant le mot «cybernétique»:

get_elements_by_inner("Cybernetic")

entrez la description de l'image ici

Cybernétique
la source
Cela renvoie vrai ou faux mais pas l'élément.
T3rm1
Vous pouvez utiliser la condition de vérité pour parcourir les éléments récupérés et récupérer tout ce dont vous avez besoin parmi ces éléments. Voir la réponse mise à jour.
Cybernetic
4

J'ai trouvé l'utilisation de la nouvelle syntaxe un peu plus courte par rapport aux autres réponses. Alors voici ma proposition:

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
la source
2

Pour obtenir la méthode de filtrage de user1106925 fonctionnant dans <= IE11 si nécessaire

Vous pouvez remplacer l'opérateur de diffusion par:

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

et l'appel comprend avec a.textContent.match("your search term")

qui fonctionne assez bien:

[].slice.call(document.querySelectorAll("a"))
   .filter(a => a.textContent.match("your search term"))
   .forEach(a => console.log(a.textContent))
Alkie
la source
J'aime cette méthode. Vous pouvez également à la Array.fromplace de [].slice.call. Par exemple: Array.from(document.querySelectorAll('a'))
Richard
1

Bien qu'il soit possible de se débrouiller avec le texte intérieur, je pense que vous vous dirigez dans la mauvaise direction. Cette chaîne interne est-elle générée dynamiquement? Si tel est le cas, vous pouvez donner à la balise une classe ou - mieux encore - un ID lorsque le texte y entre. Si c'est statique, c'est encore plus facile.

Zack Marrapese
la source
1

Vous pouvez utiliser a TreeWalkerpour parcourir les nœuds DOM, localiser tous les nœuds de texte contenant le texte et renvoyer leurs parents:

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
la source
1

Cela fait le travail.
Renvoie un tableau de nœuds contenant 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())
    );
  }
avalanche1
la source
0

Je pense que vous devrez être un peu plus précis pour que nous puissions vous aider.

  1. Comment trouvez-vous cela? Javascript? PHP? Perl?
  2. Pouvez-vous appliquer un attribut ID à la balise?

Si le texte est unique (ou vraiment, si ce n'est pas le cas, mais que vous devez parcourir un tableau), vous pouvez exécuter une expression régulière pour le trouver. Utiliser preg_match () de PHP fonctionnerait pour cela.

Si vous utilisez Javascript et pouvez insérer un attribut ID, vous pouvez utiliser getElementById ('id'). Vous pouvez ensuite accéder aux attributs de l'élément retourné via le DOM: https://developer.mozilla.org/en/DOM/element.1 .

Jeff Meyers
la source
0

J'ai juste besoin d'un moyen d'obtenir l'élément qui contient un texte spécifique et c'est ce que j'ai trouvé.

Utilisez document.getElementsByInnerText()pour obtenir plusieurs éléments (plusieurs éléments peuvent avoir le même texte exact), et utilisez document.getElementByInnerText()pour obtenir un seul élément (première correspondance).

En outre, vous pouvez localiser la recherche en utilisant un élément (par exemple someElement.getElementByInnerText()) au lieu de document.

Vous devrez peut-être le modifier pour le rendre multi-navigateur ou répondre à vos besoins.

Je pense que le code est explicite, je vais donc le laisser tel quel.

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
la source