Javascript.querySelector найти <div> по внутреннему ТЕКСТ</div>

Как я могу найти DIV с определенным текстом? Например:

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

Пытаясь использовать что-то вроде этого:

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

Но, конечно, это не сработает. Как мне это сделать?

Ответ 1

Вопрос OP - это простой JavaScript, а не jQuery. Хотя есть много ответов, и мне нравится @Pawan Nogariya ответ, пожалуйста, проверьте эту альтернативу.

Вы можете использовать XPATH в JavaScript. Подробнее о статье MDN здесь.

Метод document.evaluate() оценивает запрос/выражение XPATH. Таким образом, вы можете передавать выражения XPATH, переходить в документ HTML и находить нужный элемент.

В XPATH вы можете выбрать элемент, используя текстовый узел, такой как следующий, whch получает div, у которого есть следующий текстовый узел.

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

Чтобы получить элемент, содержащий некоторый текст, используйте следующее:

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

Метод contains() в XPATH принимает узел как первый параметр и текст для поиска в качестве второго параметра.

Проверьте это шлепнуть здесь, это пример использования XPATH в JavaScript

Вот фрагмент кода:

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

Как вы можете видеть, я могу захватить элемент HTML и изменить его, как мне нравится.

Ответ 2

Поскольку вы спросили об этом в javascript, чтобы у вас было что-то вроде этого

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

И тогда назовите это так

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

Ответ 3

Вы можете использовать это довольно простое решение:

Array.from(document.querySelectorAll('div'))
  .find(el => el.textContent === 'SomeText, text continues.');
  1. Array.from преобразует NodeList в массив (для этого используются несколько методов, например, оператор спреда или срез)

  2. Результат, являющийся теперь массивом, позволяет использовать метод Array.find, тогда вы можете вставить любой предикат. Вы также можете проверить textContent с регулярным выражением или любым другим, что вам нравится.

Обратите внимание, что Array.from и Array.find являются функциями ES2015. Те могут быть совместимы со старыми браузерами, такими как IE10 без транспилятора:

Array.prototype.slice.call(document.querySelectorAll('div'))
  .filter(function (el) {
    return el.textContent === 'SomeText, text continues.'
  })[0];

Ответ 4

Это решение делает следующее:

  • Использует оператор распространения ES6 для преобразования NodeList всех div в массив.

  • Предоставляет вывод, если div содержит строку запроса, а не только если она точно равна строке запроса (что происходит для некоторых других ответов). Например, он должен предоставлять вывод не только для "SomeText", но также для "SomeText, текст продолжается".

  • Выводит все содержимое div, а не только строку запроса. например, для "SomeText, text continue" он должен выводить целую строку, а не только "SomeText".

  • Позволяет нескольким div содержать строку, а не только один 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>

Ответ 5

Лучше всего посмотреть, есть ли у вас родительский элемент div, который вы запрашиваете. Если так, получите родительский элемент и выполните элемент element.querySelectorAll("div"). Как только вы получите nodeList применить фильтр на нем по свойству innerText. Предположим, что родительский элемент div, который мы запрашиваем, имеет id container. Обычно вы можете напрямую обращаться к контейнеру с идентификатора, но пусть это делает правильный путь.

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

Так что это.

Ответ 6

Если вы не хотите использовать jquery или что-то в этом роде, вы можете попробовать следующее:

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

Когда у вас есть узлы в массиве, содержащие текст, вы можете что-то с ними делать. Как предупреждать каждого или печатать на консоль. Одно из предостережений состоит в том, что это может не обязательно захватить divs как таковое, это захватит родительский элемент текстового блока, который имеет текст, который вы ищете.

Ответ 7

В Google это лучший результат для тех, кому нужно найти узел с определенным текстом. В результате обновления ноделист теперь можно выполнять в современных браузерах без необходимости его преобразования в массив.

Решение может использовать forEach так же.

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

Это помогло мне найти текст поиска/замены внутри нодлиста, когда обычный селектор не мог выбрать только один узел, поэтому мне пришлось фильтровать каждый узел один за другим, чтобы проверить его на иглу.

Ответ 8

Используйте XPath и document.evaluate(), и обязательно используйте text(), а не. для аргумента contains(), иначе у вас будет весь HTML-код или внешний элемент div.

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

или игнорировать начальные и конечные пробелы

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

или соответствуют всем типам тегов (div, h1, p и т.д.)

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

Затем повторить

let thisHeading;
while(thisHeading = headings.iterateNext()){
    // thisHeading contains matched node
}

Ответ 9

Здесь подход 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';
}