Javascript .querySelector는 innerTEXT로 <div>를 찾습니다.


109

특정 텍스트로 DIV를 어떻게 찾을 수 있습니까? 예를 들면 :

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

다음과 같이 사용하려고합니다.

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

그러나 물론 작동하지 않습니다. 내가 어떻게 해?


할 수 있더라도 모든 div를 가져와 innerText 속성을 통해 필터링하는 것보다 빠르지는 않습니다. 그러니 수동으로하는 것이 어떻습니까?
Redu

답변:


100

OP의 질문은 jQuery가 아닌 일반 JavaScript 에 관한 것 입니다. 많은 답변이 있고 @Pawan Nogariya 답변을 좋아하지만 이 대안을 확인하십시오.

JavaScript에서 XPATH 를 사용할 수 있습니다 . MDN 기사에 대한 자세한 정보는 여기 .

document.evaluate()메서드는 XPATH 쿼리 / 표현식을 평가합니다. 따라서 거기에 XPATH 표현식을 전달하고 HTML 문서로 이동하여 원하는 요소를 찾을 수 있습니다.

XPATH에서 다음과 같은 텍스트 노드로 요소를 선택할 수 있습니다. whch는 다음 텍스트 노드가있는 요소를 가져옵니다 div.

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

일부 텍스트를 포함하는 요소를 얻으려면 다음을 사용하십시오.

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

contains()XPATH 의 메소드는 노드를 첫 번째 매개 변수로 사용하고 텍스트를 두 번째 매개 변수로 검색합니다.

여기 에서이 plunk를 확인하십시오. 이것은 JavaScript에서 XPATH를 사용한 예제입니다.

다음은 코드 스 니펫입니다.

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 요소를 가져 와서 원하는대로 수정할 수 있습니다.


감사합니다! 잘 작동합니다! 하지만이 텍스트에서 한 단어 만 가져와야하는 경우 "thisHeading.textContent"를 "console.log"하는 방법은 무엇입니까? 예 : '// div [contains (., \'/ You login (. *) times this session / \ ')]'그런 다음 alert (thisHeading.textContent. $ 1)
passwd

좋아, 나는 이렇게한다 :alert(thisHeading.textContent.replace(/.*You have login (.*) times.*/,'$1')) ;
passwd

@passwd, 당신은 그렇게 할 수 없습니다. 정규식은 XPATH 1.0에서 지원되지 않습니다 ( .evaluate()사용합니다. 제가 틀렸다면 누군가 정정 해주십시오). 첫째로, 정규식과 일치하는 것을 검색 할 수 없습니다. 둘째, .textContent속성은 요소의 텍스트 노드를 반환합니다. 이 텍스트에서 값을 가져 오려면 정규식과 일치하는 일종의 함수를 만들고 그룹에서 일치하는 값을 반환하여 명시 적으로 처리해야합니다.이를 위해 별도의 스레드에서 새 질문을 만드십시오.
gdyrrahitis

Internet Explorer : 지원되지 않습니다. 그러나 Edge에서 지원됩니다. 버전 측면에서 그게 무슨 뜻인지 잘 모르겠습니다.
Rolf

찾고있는 요소가 누락 된 경우 오류를 어떻게 처리해야합니까?
nenito

72

이 매우 간단한 솔루션을 사용할 수 있습니다.

Array.from(document.querySelectorAll('div'))
  .find(el => el.textContent === 'SomeText, text continues.');
  1. Array.from(확산 연산자 또는 슬라이스와 같은 이렇게 여러 방법이있다) 배열로 노드 목록을 변환 할

  2. 결과는 이제 배열이되어 Array.find메소드 를 사용할 수있게되며 , 그런 다음 모든 술어를 넣을 수 있습니다. 정규식 또는 원하는대로 textContent를 확인할 수도 있습니다.

참고 Array.fromArray.findES2015 기능은 다음과 같습니다. 트랜스 파일러없이 IE10과 같은 이전 브라우저와 호환됩니다.

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

2
여러 요소를 찾을하려는 경우, 교체 find와 함께 filter.
RubbelDieKatz

38

당신이 자바 스크립트에서 요청했기 때문에 다음과 같은 것을 가질 수 있습니다.

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

1
이것이 작동하는 것처럼 보이지만 그 대가로 나는 이것 만 얻습니다 :[object HTMLDivElement],[object HTMLDivElement]
passwd

예, 일치하는 텍스트가있는 div를 가져 오면 다음과 같이 내부 텍스트 메서드를 호출 할 수 있습니다. foundDivs[0].innerText간단합니다
Pawan Nogariya

20

이 솔루션은 다음을 수행합니다.

  • ES6 확산 연산자를 사용하여 모든 div의 NodeList를 배열 로 변환합니다 .

  • (가) 경우 출력을 제공 div 포함 쿼리 문자열을 정확히 아닌 경우, 동일 (다른 답변의 일부 발생하는) 쿼리 문자열을. 예 : 'SomeText'뿐만 아니라 'SomeText, text continue'에 대한 출력도 제공해야합니다.

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


3
나는 이것을 사랑한다. 깨끗하고 간결하며 이해하기 쉬운 모든 것이 동시에 가능합니다.
ba_ul dec.

2
확실히 끔찍하게 비효율적입니까? innerHTML최상위 <div>s의 크기를 생각하십시오 . div먼저 자식을 포함하는를 필터링해야합니다 . 또한 의심 document.getElementsByTagName('div')이 더 빠를 수 있지만 확실하게 벤치마킹 할 것입니다.
Timmmm

이것은 나에게 좋습니다. 처음에는 좋은 선택기를 설정할 수 있습니다. 테이블에만있을 수 있다는 것을 이미 알고 있기 때문입니다. 감사합니다
gsalgadotoledo

10

쿼리하는 div의 상위 요소가 있는지 확인하는 것이 가장 좋습니다. 그렇다면 부모 요소를 가져 와서 element.querySelectorAll("div"). 일단 속성 nodeList에 필터를 적용하십시오 innerText. 우리가 쿼리되는 사업부의 부모 요소가 있다고 가정 idcontainer. 일반적으로 ID에서 직접 컨테이너에 액세스 할 수 있지만 적절한 방법으로합시다.

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

그게 다입니다.


이것은 나를 위해 대신 innerText와의 innerHTML을 함께 일
체이스 Sandmann

5

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

텍스트를 포함하는 배열에 노드가 있으면 작업을 수행 할 수 있습니다. 각각 경고하거나 콘솔에 인쇄하십시오. 한 가지주의 할 점은 이것이 반드시 div 자체를 가져 오지 않을 수도 있다는 것입니다. 그러면 찾고있는 텍스트가있는 텍스트 노드의 부모를 가져옵니다.


3

데이터 속성의 텍스트 길이에는 제한이 없으므로 데이터 속성을 사용하십시오! 그런 다음 일반 CSS 선택기를 사용하여 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>

이상적으로는 문서로드시 데이터 속성 설정 부분을 수행하고 성능을 위해 querySelectorAll 선택기의 범위를 좁 힙니다.


2

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

이것은 일반 선택기가 하나의 노드 만 선택할 수 없을 때 노드 목록 내에서 텍스트를 찾고 / 바꾸는 데 도움이되었으므로 바늘을 확인하기 위해 각 노드를 하나씩 필터링해야했습니다.


2

XPath 및 document.evaluate ()를 사용하고. 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
}

이 메서드를 사용하여 요소에 클래스를 추가 할 수 있습니까? 예thisheading.setAttribute('class', "esubject")
Matthew

요소가 있으면 확실합니다. 그러나, element.classList.add ( "esubject") :)하지만 사용하는 것이 좋습니다
스티븐 Spungin

1

다음은 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';
}

0

비슷한 문제가있었습니다.

arg의 텍스트를 포함하는 모든 요소를 ​​반환하는 함수입니다.

이것은 나를 위해 작동합니다.

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

여기에는 이미 많은 훌륭한 솔루션이 있습니다. 그러나보다 능률적 인 솔루션을 제공하고 querySelector 동작 및 구문에 대한 아이디어를 유지하기 위해 Object 를 확장하는 솔루션을 선택했습니다. 몇 가지 프로토 타입 함수로 . 이 두 함수는 모두 텍스트 일치를 위해 정규식을 사용하지만 문자열은 느슨한 검색 매개 변수로 제공 될 수 있습니다.

다음 기능을 구현하기 만하면됩니다.

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

이러한 함수를 구현하면 이제 다음과 같이 호출 할 수 있습니다.

  • document.queryInnerTextAll('div.link', 'go');
    그러면 innerText에서 go 라는 단어 포함 된 링크 클래스가 포함 된 모든 div 를 찾습니다 (예 : Go Left 또는 GO down 또는 go right 또는 It 's Go od ).
  • document.queryInnerText('div.link', 'go');
    이것은 첫 번째 일치하는 요소 만 반환한다는 점을 제외하면 위의 예와 똑같이 작동합니다.
  • document.queryInnerTextAll('a', /^Next$/);
    정확한 Next (대소 문자 구분) 텍스트가있는 모든 링크를 찾습니다 . 다른 텍스트와 함께 Next 라는 단어가 포함 된 링크는 제외 됩니다.
  • document.queryInnerText('a', /next/i);
    대소 문자에 관계없이 next 라는 단어가 포함 된 첫 번째 링크를 찾습니다 (예 : Next Page 또는 Go to next ).
  • e = document.querySelector('#page');
    e.queryInnerText('button', /Continue/);
    그러면 컨테이너 요소 내에서 Continue (대소 문자 구분) 텍스트가 포함 된 버튼에 대한 검색이 수행 됩니다. (예 : 계속 또는 다음으로 계속 하지만 계속 하지 않음 )
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.