特定のテキストを含むDIVを見つけるにはどうすればよいですか?例えば:
<div>
SomeText, text continues.
</div>
次のようなものを使用しようとしています:
var text = document.querySelector('div[SomeText*]').innerTEXT;
alert(text);
もちろん、それは機能しません。どうすればできますか?
特定のテキストを含むDIVを見つけるにはどうすればよいですか?例えば:
<div>
SomeText, text continues.
</div>
次のようなものを使用しようとしています:
var text = document.querySelector('div[SomeText*]').innerTEXT;
alert(text);
もちろん、それは機能しません。どうすればできますか?
回答:
OPの質問は、jQueryではなくプレーンJavaScriptについてです。答えはたくさんあり、@ Pawan Nogariya answerが好きですが、この代替案をチェックしてください。
JavaScriptでXPATHを使用できます。MDN記事の詳細については、こちらをご覧ください。
このdocument.evaluate()
メソッドは、XPATHクエリ/式を評価します。そこで、XPATH式をそこに渡し、HTML文書を走査して、目的の要素を見つけることができます。
XPATHでは、次のようなテキストノードによって要素を選択できますdiv
。この場合、次のテキストノードを持つを取得します。
//div[text()="Hello World"]
一部のテキストを含む要素を取得するには、以下を使用します。
//div[contains(., 'Hello')]
contains()
XPATH のメソッドは、ノードを最初のパラメーターとして、検索するテキストを2番目のパラメーターとして受け取ります。
ここでこのプランクを確認してください。これは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要素を取得して、好きなように変更できます。
alert(thisHeading.textContent.replace(/.*You have login (.*) times.*/,'$1')) ;
.evaluate()
正規表現はXPATH 1.0(使用しています。間違っている場合は誰かが私を修正してください)ではサポートされていないため、最初に、正規表現に一致するものを検索できません。次に、.textContent
プロパティは要素のテキストノードを返します。このテキストから値を取得する場合は、おそらく正規表現に一致し、一致する値をグループで返す関数を作成することによって、明示的に処理する必要があります。そのためには、別のスレッドで新しい質問を作成します。
このかなりシンプルなソリューションを使用できます:
Array.from(document.querySelectorAll('div'))
.find(el => el.textContent === 'SomeText, text continues.');
Array.from
アレイへのNodeListを変換する(拡散オペレータまたはスライスのように、これを行うために複数の方法が存在します)
結果は配列になり、Array.find
メソッドを使用できるようになり、任意の述部を入れることができます。正規表現や好きなものでtextContentをチェックすることもできます。
なお、Array.from
及びArray.find
ES2015機能です。TeはトランスパイラーなしでIE10のような古いブラウザーと互換性があります。
Array.prototype.slice.call(document.querySelectorAll('div'))
.filter(function (el) {
return el.textContent === 'SomeText, text continues.'
})[0];
find
とfilter
。
あなたは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
[object HTMLDivElement],[object HTMLDivElement]
foundDivs[0].innerText
な単純な方法で呼び出すことができます
このソリューションは次のことを行います。
ES6スプレッド演算子を使用して、すべてdiv
ののNodeListを配列に変換します。
がクエリ文字列と完全に一致するだけでなく、クエリ文字列div
が含まれている場合に出力を提供します(他の回答の一部で発生します)。たとえば、「SomeText」だけでなく、「SomeText、テキストが続く」にも出力を提供する必要があります。
div
クエリ文字列だけでなく、コンテンツ全体を出力します。たとえば、「SomeText、テキストが続く」の場合は、「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>
innerHTML
一番上<div>
のsの大きさを考えてください。div
最初に子を含むを除外する必要があります。また、容疑者document.getElementsByTagName('div')
はより速いかもしれませんが、私は確かにベンチマークをします。
照会するdivの親要素があるかどうかを確認するのが最善です。もしそうなら、親要素を取得してを実行しelement.querySelectorAll("div")
ます。取得したらnodeList
、innerText
プロパティにフィルターを適用します。我々が照会されていることをdiv要素の親要素が持っていると仮定id
するとcontainer
。通常はidから直接コンテナにアクセスできますが、適切な方法で実行してみましょう。
var conty = document.getElementById("container"),
divs = conty.querySelectorAll("div"),
myDiv = [...divs].filter(e => e.innerText == "SomeText");
以上です。
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]
}
テキストを含む配列内のノードを取得したら、それらを使用して何かを行うことができます。それぞれに警告するか、コンソールに出力します。1つの注意点は、これは必ずしもdiv自体を取得する必要がない場合があることです。これは、探しているテキストを含むtextnodeの親を取得します。
データ属性のテキストの長さに制限がないため、データ属性を使用してください!そして、通常の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セレクターを少し絞り込みます。
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
}
});
これは、通常のセレクターが1つのノードしか選択できないときにノードリスト内でテキストを検索/置換するのに役立ちました。そのため、針をチェックするために各ノードを1つずつフィルターする必要がありました。
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
}
thisheading.setAttribute('class', "esubject")
これが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';
}
同様の問題がありました。
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)))
}
ここにはすでに多くの優れたソリューションがあります。ただし、より合理化されたソリューションを提供するために、querySelectorの動作と構文のアイデアに合わせてもう1つ、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');
document.queryInnerText('div.link', 'go');
document.queryInnerTextAll('a', /^Next$/);
document.queryInnerText('a', /next/i);
e = document.querySelector('#page');
e.queryInnerText('button', /Continue/);