Javascript .querySelector, <div> öğesini innerTEXT ile bul


109

DIV'yi belirli bir metinle nasıl bulabilirim? Örneğin:

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

Bunun gibi bir şey kullanmaya çalışıyorum:

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

Ama elbette işe yaramayacak. Nasıl yapabilirim?


Bunu yapabilseniz bile, tüm div'leri almaktan ve onları innerText özelliği üzerinden filtrelemekten daha hızlı olmazdı. Öyleyse neden elle yapmıyorsun?
Redu

Olası yineleme:
jQuery'nin

Yanıtlar:


100

OP'nin sorusu jQuery ile değil , düz JavaScript ile ilgilidir . Çok sayıda cevap olmasına ve @Pawan Nogariya cevabını beğenmeme rağmen , lütfen bu alternatifi kontrol edin.

XPATH'yi JavaScript'te kullanabilirsiniz . MDN makalesi hakkında daha fazla bilgiyi burada bulabilirsiniz .

document.evaluate()Yöntem, bir XPATH sorgu / ifade değerlendirir. Böylece oraya XPATH ifadelerini iletebilir, HTML belgesine geçebilir ve istenen öğeyi bulabilirsiniz.

XPATH'de, aşağıdaki gibi metin düğümüyle, aşağıdaki metin düğümüne sahip olan bir eleman seçebilirsiniz div.

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

Metin içeren bir öğe almak için aşağıdakileri kullanın:

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

contains()XPATH yöntem birinci ve ikinci parametrelerle olarak aramak için metin olarak bir düğüm alır.

Buradaki bu boşluğu kontrol edin , bu JavaScript'te XPATH kullanımına bir örnek

İşte bir kod parçacığı:

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

Gördüğünüz gibi, HTML öğesini alıp istediğim gibi değiştirebiliyorum.


Teşekkür ederim! Harika çalışıyor! Ancak bu metinden yalnızca bir kelime almam gerekirse "console.log" "thisHeading.textContent" nasıl yapılır? Örneğin: '// div [şunu içerir (., \' / Bu oturumda (. *) Kez oturum açarsınız / \ ')]' ve ardından uyarı (thisHeading.textContent. $ 1)
passwd

Tamam, şu şekilde yapıyorum:alert(thisHeading.textContent.replace(/.*You have login (.*) times.*/,'$1')) ;
passwd

@passwd, bunu yapamazsınız. Regex XPATH 1.0'da desteklenmez ( .evaluate()kullanır. Yanlışsam lütfen birisi beni düzeltir), bu yüzden öncelikle normal ifadeyle eşleşen bir şey arayamazsınız. İkinci olarak, .textContentözellik, öğenin metin düğümünü döndürür. Bu metinden bir değer elde etmek istiyorsanız, muhtemelen bir normal ifadeyle eşleşen ve gruptaki eşleşen değeri döndüren bir tür işlev oluşturarak, bunu açıkça ele almalısınız. Bunun için ayrı bir konu grubunda yeni bir soru oluşturun.
gdyrrahitis

Internet Explorer: Destek yok. Ancak Edge'de desteklenir. Bunun versiyon açısından ne anlama geldiğinden emin değilim.
Rolf

Aradığım öğenin eksik olması durumunda bir hata nasıl ele alınmalı?
nenito

72

Bu oldukça basit çözümü kullanabilirsiniz:

Array.from(document.querySelectorAll('div'))
  .find(el => el.textContent === 'SomeText, text continues.');
  1. Array.from(Yayılma operatörü veya dilim gibi bunu yapmak için birden çok yöntem vardır) bir diziye nodelist dönüştürür

  2. Sonucun artık bir dizi olması Array.findyöntemi kullanmaya izin verir , daha sonra herhangi bir yüklemi koyabilirsiniz. TextContent'i bir normal ifadeyle veya ne isterseniz kontrol edebilirsiniz.

Not Array.fromve Array.findES2015 özellikleridir. Transpiler olmadan IE10 gibi eski tarayıcılarla uyumlu olun:

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

2
Birden unsurları bulmak isterseniz, değiştirin findile filter.
RubbelDieKatz

38

Bunu javascript ile sorduğun için böyle bir şeye sahip olabilirsin

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

Ve sonra böyle çağır

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

1
Bu işe yarıyor gibi görünüyor, ancak karşılığında sadece şunu alıyorum:[object HTMLDivElement],[object HTMLDivElement]
passwd

Evet, içinde eşleşen metin bulunan div'leri alacaksınız ve sonra iç metin yöntemini şöyle çağırabilirsiniz foundDivs[0].innerText, bu kadar basit
Pawan Nogariya

20

Bu çözüm aşağıdakileri yapar:

  • Tüm e'lerin NodeList'ini divbir diziye dönüştürmek için ES6 yayılma operatörünü kullanır .

  • Yalnızca sorgu dizesine tam olarak eşitse (diğer yanıtların bazıları için olur) değil, sorgu dizesini div içeriyorsa çıktı sağlar . Örneğin, sadece 'Bir Metin' için değil, aynı zamanda 'Bir Metin, metin devam eder' için de çıktı sağlamalıdır.

  • divYalnızca sorgu dizesini değil , tüm içeriği verir. Örneğin, 'Bir Metin, metin devam eder' için sadece 'Bir Metin' değil, tüm dizeyi çıktı olarak vermelidir.

  • Birden çok divURL'nin dizeyi içermesine izin verir , yalnızca bir tane değil 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>


3
Bunu seviyorum. Temiz, özlü ve anlaşılır - hepsi aynı anda.
ba_ul

2
Kesinlikle korkunç derecede verimsiz mi? En iyileriniz için ne kadar büyük innerHTMLolduğunu düşünün <div>. Önce divçocuk içeren e- postaları filtrelemelisiniz . Ayrıca şüpheli document.getElementsByTagName('div')daha hızlı olabilir ama emin olmak için kıyaslama yapardım.
Timmmm

Bu benim için harika, başlangıçta iyi bir seçici belirleyebilirim çünkü bunun sadece bir masada olabileceğini zaten biliyorum, harika, teşekkürler
gsalgadotoledo

10

Sorguladığınız div öğesinin bir üst öğesine sahip olup olmadığınızı en iyi şekilde görürsünüz. Eğer öyleyse, ana öğeyi alın ve bir element.querySelectorAll("div"). Mülk nodeListüzerinde bir filtre uyguladıktan sonra innerText. Biz sorguluyorsunuz div bir ana öğe bir olduğunu varsayalım idarasında container. Normalde konteynere doğrudan id'den erişebilirsiniz ama hadi bunu doğru şekilde yapalım.

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

İşte bu kadar.


Bu benim için çalıştı, ancak innerText yerine innerHTML ile
Chase Sandmann

5

Jquery veya buna benzer bir şey kullanmak istemiyorsanız, şunu deneyebilirsiniz:

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

Metni içeren bir dizide düğümlere sahip olduğunuzda onlarla bir şeyler yapabilirsiniz. Her birini uyarın veya konsola yazdırın. Bir uyarı, bunun mutlaka kendi başına div'leri yakalayamayacağıdır, bu, aradığınız metne sahip metin düğümünün ebeveynini yakalayacaktır.


3

Bir veri özniteliğindeki metnin uzunluğu için herhangi bir sınırlama olmadığından, veri özniteliklerini kullanın! Ve sonra OP'nin istediği gibi öğelerinizi seçmek için normal css seçicileri kullanabilirsiniz.

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>

İdeal olarak, veri özniteliği ayarlama bölümünü belge yüklerken yaparsınız ve performans için querySelectorAll seçiciyi biraz daraltırsınız.


2

Google bunu, belirli bir metne sahip bir düğüm bulması gerekenler için en iyi sonuç olarak alır. Güncelleme yoluyla, bir nodelist artık modern tarayıcılarda bir diziye dönüştürmek zorunda kalmadan yinelenebilir.

Çözüm, her biri için kullanılabilir.

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

Bu, normal bir seçici yalnızca bir düğümü seçemediğinde, iğneyi kontrol etmek için her düğümü tek tek filtrelemek zorunda kaldığında bir düğüm listesi içinde bir metin bul / değiştir yapmam için çalıştı.


2

XPath ve document.evaluate () kullanın ve text () kullandığınızdan emin olun. contains () bağımsız değişkeni için yoksa tüm HTML'ye veya en dıştaki div öğesine sahip olursunuz.

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

veya baştaki ve sondaki boşlukları yoksay

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

veya tüm etiket türleriyle eşleşir (div, h1, p, vb.)

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

Sonra tekrarlayın

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

Bu yöntem bir elemana sınıf eklemek için kullanılabilir mi? örneğinthisheading.setAttribute('class', "esubject")
Matthew

Elemana sahip olduğunuzda, elbette. Ancak, element.classList.add ("esubject") kullanmak daha iyidir :)
Steven Spungin

1

İşte XPath yaklaşımı, ancak minimum XPath jargonu ile.

Öğe özellik değerlerine göre düzenli seçim (karşılaştırma için):

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

Öğe içindeki metne dayalı XPath seçimi.

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

Ve işte metin daha değişken olduğu için büyük / küçük harfe duyarsızlıkla:

// 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

Benim de benzer bir problemim vardı.

Arg'den metin içeren tüm öğeleri döndüren işlev.

Bu benim için çalışıyor:

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

Burada zaten birçok harika çözüm var. Ancak, daha akıcı bir çözüm ve bir querySelector davranışı ve sözdizimi fikrine uygun bir çözüm sağlamak için, birkaç prototip işleviyle Object'i genişleten bir çözüm seçtim . Bu işlevlerin her ikisi de eşleşen metin için normal ifadeler kullanır, ancak bir dizge gevşek bir arama parametresi olarak sağlanabilir.

Aşağıdaki işlevleri uygulamanız yeterlidir:

// find all elements with inner text matching a given regular expression
// args: 
//      selector: string query selector to use for identifying elements on which we 
//                should check innerText
//      regex: A regular expression for matching innerText; if a string is provided,
//             a case-insensitive search is performed for any element containing the string.
Object.prototype.queryInnerTextAll = function(selector, regex) {
    if (typeof(regex) === 'string') regex = new RegExp(regex, 'i'); 
    const elements = [...this.querySelectorAll(selector)];
    const rtn = elements.filter((e)=>{
        return e.innerText.match(regex);
    });
    
    return rtn.length === 0 ? null : rtn
}

// find the first element with inner text matching a given regular expression
// args: 
//      selector: string query selector to use for identifying elements on which we 
//                should check innerText
//      regex: A regular expression for matching innerText; if a string is provided,
//             a case-insensitive search is performed for any element containing the string.
Object.prototype.queryInnerText = function(selector, text){
    return this.queryInnerTextAll(selector, text)[0];
}

Bu işlevler uygulandığında, artık aşağıdaki gibi çağrılar yapabilirsiniz:

  • document.queryInnerTextAll('div.link', 'go');
    Bu, tüm bulacağını div'leri içeren bağlantı kelime ile sınıfını halindeyken (. Örn innerText içinde git Sol veya aşağı GO veya sağa gitmek veya It en Git od )
  • document.queryInnerText('div.link', 'go');
    Bu, yalnızca ilk eşleşen öğeyi döndürmesi dışında yukarıdaki örnekle tam olarak çalışacaktır.
  • document.queryInnerTextAll('a', /^Next$/);
    Tam olarak Sonraki metnini içeren tüm bağlantıları bulun (büyük / küçük harfe duyarlı). Bu, diğer metinle birlikte Sonraki kelimesini içeren bağlantıları hariç tutar .
  • document.queryInnerText('a', /next/i);
    Durumdan bağımsız olarak sonraki kelimesini içeren ilk bağlantıyı bulun (ör. Sonraki Sayfaya veya Sonrakine Git )
  • e = document.querySelector('#page');
    e.queryInnerText('button', /Continue/);
    Bu, Devam (büyük / küçük harfe duyarlı) metnini içeren bir düğme için kap öğesi içinde bir arama gerçekleştirir . (ör. Devam Et veya Sonrakine Devam Et ama devam etmeyin )
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.