回答:
var text = $(".title").contents().filter(function() {
return this.nodeType == Node.TEXT_NODE;
}).text();
これはcontents
選択された要素のを取得し、それにフィルター関数を適用します。filter関数は、テキストノード(つまり、を含むノードnodeType == Node.TEXT_NODE
)のみを返します。
text()
ため、必要filter
です。
jQuery("*").each(function() { console.log(this.nodeType); })
を取得しました。
null
、戻り値を取得することがあります。
要素の最初のテキストノードの値を取得する場合は、次のコードが機能します。
var oDiv = document.getElementById("MyDiv");
var firstText = "";
for (var i = 0; i < oDiv.childNodes.length; i++) {
var curNode = oDiv.childNodes[i];
if (curNode.nodeName === "#text") {
firstText = curNode.nodeValue;
break;
}
}
あなたはここでこれを実際に見ることができます:http : //jsfiddle.net/ZkjZJ/
curNode.nodeType == 3
代わりに使ってもいいと思いますnodeName
。
curNode.nodeType == Node.TEXT_NODE
(数値比較は高速ですが、curNode.nodeType == 3は読み取れません-どのノードに番号3がありますか?)
curNode.NodeType === Node.TEXT_NODE
。この比較は、未知の可能な反復のループ内で発生しています。2つの小さな数値を比較することは、さまざまな長さの文字列を比較するよりも優れています(時間とスペースに関する考慮事項)。この状況で正しい質問は、「ノードの種類/タイプは何ですか?」であり、「名前は何ですか?」ではありません。developer.mozilla.org/en-US/docs/Web/API/Node/nodeType
childNodes
場合は、要素ノードに複数のテキストノードを含めることができることを確認してください。一般的なソリューションでは、対象とする要素ノード内のテキストノードのインスタンスを指定する必要がある場合があります(1番目、2番目、3番目など)。
「複雑な」要素や深くネストされた要素に役立つ別のネイティブJSソリューションは、NodeIteratorを使用することです。プットNodeFilter.SHOW_TEXT
第二引数(「whatToShow」)、および反復を超える要素の単なるテキストノードの子として。
var root = document.querySelector('p'),
iter = document.createNodeIterator(root, NodeFilter.SHOW_TEXT),
textnode;
// print all text nodes
while (textnode = iter.nextNode()) {
console.log(textnode.textContent)
}
<p>
<br>some text<br>123
</p>
も使用できますTreeWalker
。2つの違いNodeIterator
は、単純な線形反復子であり、TreeWalker
兄弟や祖先を介してナビゲートすることもできます。
まず、DOMでテキストを検索するときは常にこのことを覚えておいてください。
この問題は、XML / HTMLの構造に注意を向けさせるでしょう。
この純粋なJavaScriptの例では、他の種類のノードとインターリーブできる複数のテキストノードの可能性を説明します。ただし、最初は空白の判断にパスせず、そのフィルタリングタスクは他のコードに任せています。
このバージョンNodeList
では、呼び出し/クライアントコードからaを渡します。
/**
* Gets strings from text nodes. Minimalist. Non-robust. Pre-test loop version.
* Generic, cross platform solution. No string filtering or conditioning.
*
* @author Anthony Rutledge
* @param nodeList The child nodes of a Node, as in node.childNodes.
* @param target A positive whole number >= 1
* @return String The text you targeted.
*/
function getText(nodeList, target)
{
var trueTarget = target - 1,
length = nodeList.length; // Because you may have many child nodes.
for (var i = 0; i < length; i++) {
if ((nodeList[i].nodeType === Node.TEXT_NODE) && (i === trueTarget)) {
return nodeList[i].nodeValue; // Done! No need to keep going.
}
}
return null;
}
もちろん、node.hasChildNodes()
最初にテストすることにより、事前テストfor
ループを使用する必要はありません。
/**
* Gets strings from text nodes. Minimalist. Non-robust. Post-test loop version.
* Generic, cross platform solution. No string filtering or conditioning.
*
* @author Anthony Rutledge
* @param nodeList The child nodes of a Node, as in node.childNodes.
* @param target A positive whole number >= 1
* @return String The text you targeted.
*/
function getText(nodeList, target)
{
var trueTarget = target - 1,
length = nodeList.length,
i = 0;
do {
if ((nodeList[i].nodeType === Node.TEXT_NODE) && (i === trueTarget)) {
return nodeList[i].nodeValue; // Done! No need to keep going.
}
i++;
} while (i < length);
return null;
}
ここでは、関数getTextById()
は2つのヘルパー関数を使用しています:getStringsFromChildren()
およびfilterWhitespaceLines()
。
getStringsFromChildren()
/**
* Collects strings from child text nodes.
* Generic, cross platform solution. No string filtering or conditioning.
*
* @author Anthony Rutledge
* @version 7.0
* @param parentNode An instance of the Node interface, such as an Element. object.
* @return Array of strings, or null.
* @throws TypeError if the parentNode is not a Node object.
*/
function getStringsFromChildren(parentNode)
{
var strings = [],
nodeList,
length,
i = 0;
if (!parentNode instanceof Node) {
throw new TypeError("The parentNode parameter expects an instance of a Node.");
}
if (!parentNode.hasChildNodes()) {
return null; // We are done. Node may resemble <element></element>
}
nodeList = parentNode.childNodes;
length = nodeList.length;
do {
if ((nodeList[i].nodeType === Node.TEXT_NODE)) {
strings.push(nodeList[i].nodeValue);
}
i++;
} while (i < length);
if (strings.length > 0) {
return strings;
}
return null;
}
filterWhitespaceLines()
/**
* Filters an array of strings to remove whitespace lines.
* Generic, cross platform solution.
*
* @author Anthony Rutledge
* @version 6.0
* @param textArray a String associated with the id attribute of an Element.
* @return Array of strings that are not lines of whitespace, or null.
* @throws TypeError if the textArray param is not of type Array.
*/
function filterWhitespaceLines(textArray)
{
var filteredArray = [],
whitespaceLine = /(?:^\s+$)/; // Non-capturing Regular Expression.
if (!textArray instanceof Array) {
throw new TypeError("The textArray parameter expects an instance of a Array.");
}
for (var i = 0; i < textArray.length; i++) {
if (!whitespaceLine.test(textArray[i])) { // If it is not a line of whitespace.
filteredArray.push(textArray[i].trim()); // Trimming here is fine.
}
}
if (filteredArray.length > 0) {
return filteredArray ; // Leave selecting and joining strings for a specific implementation.
}
return null; // No text to return.
}
getTextById()
/**
* Gets strings from text nodes. Robust.
* Generic, cross platform solution.
*
* @author Anthony Rutledge
* @version 6.0
* @param id A String associated with the id property of an Element.
* @return Array of strings, or null.
* @throws TypeError if the id param is not of type String.
* @throws TypeError if the id param cannot be used to find a node by id.
*/
function getTextById(id)
{
var textArray = null; // The hopeful output.
var idDatatype = typeof id; // Only used in an TypeError message.
var node; // The parent node being examined.
try {
if (idDatatype !== "string") {
throw new TypeError("The id argument must be of type String! Got " + idDatatype);
}
node = document.getElementById(id);
if (node === null) {
throw new TypeError("No element found with the id: " + id);
}
textArray = getStringsFromChildren(node);
if (textArray === null) {
return null; // No text nodes found. Example: <element></element>
}
textArray = filterWhitespaceLines(textArray);
if (textArray.length > 0) {
return textArray; // Leave selecting and joining strings for a specific implementation.
}
} catch (e) {
console.log(e.message);
}
return null; // No text to return.
}
次に、戻り値(配列、またはnull)が処理されるクライアントコードに送信されます。うまくいけば、配列には空白行ではなく、実際のテキストの文字列要素が必要です。
空の文字列は(""
)されていない、あなたが適切に有効なテキストの存在を示すために、テキストノードを必要とするので返さ。(""
)を返すと、テキストノードが存在するという誤った印象を与え、誰かがの値を変更することによってテキストを変更できると思い込む可能性があります.nodeValue
。空の文字列の場合、テキストノードは存在しないため、これは誤りです。
例1:
<p id="bio"></p> <!-- There is no text node here. Return null. -->
例2:
<p id="bio">
</p> <!-- There are at least two text nodes ("\n"), here. -->
この問題は、HTMLを間隔を空けて読みやすくする場合に発生します。これで、人間が読み取れる有効なテキストはあり"\n"
ませんが、.nodeValue
プロパティに改行()文字を含むテキストノードが残っています。
人間は、例1と2を機能的に同等であると見なします。空の要素が満たされるのを待っています。DOMは人間の推論とは異なります。これが、getStringsFromChildren()
関数がテキストノードが存在するかどうかを判断し、.nodeValue
値を配列に収集する必要がある理由です。
for (var i = 0; i < length; i++) {
if (nodeList[i].nodeType === Node.TEXT_NODE) {
textNodes.push(nodeList[i].nodeValue);
}
}
例2では、2つのテキストノードが存在getStringFromChildren()
し.nodeValue
、両方のを返します("\n"
)。ただし、filterWhitespaceLines()
正規表現を使用して、純粋な空白文字の行を除外します。
null
改行("\n"
)文字の代わりに返すことは、クライアント/呼び出しコードに嘘をついている形ですか?人間の言葉では、いいえ。DOM用語では、はい。ただし、ここでの問題は、編集ではなくテキストを取得することです。呼び出し元のコードに戻る人間のテキストはありません。
誰かのHTMLにいくつの改行文字が現れるかは決してわかりません。「2番目の」改行文字を探すカウンターの作成は信頼できません。存在しない可能性があります。
もちろん、さらに下の行で、余分な空白を含む空の要素のテキストを編集する問題<p></p>
(例2)は、要素が正確に何を含んでいるかを確認するために、段落のタグ間の1つを除くすべてのテキストノードを破棄(おそらくスキップ)することを意味します表示することになっています。
とにかく、あなたが特別なことをしている場合を除いて、どのテキストノードの.nodeValue
プロパティがあなたが編集したい真の人間が読めるテキストを持っているかを決定する方法が必要になります。filterWhitespaceLines
そこまでの道のりです。
var whitespaceLine = /(?:^\s+$)/; // Non-capturing Regular Expression.
for (var i = 0; i < filteredTextArray.length; i++) {
if (!whitespaceLine.test(textArray[i])) { // If it is not a line of whitespace.
filteredTextArray.push(textArray[i].trim()); // Trimming here is fine.
}
}
この時点で、次のような出力が表示されることがあります。
["Dealing with text nodes is fun.", "Some people just use jQuery."]
これら2つの文字列がDOM内で互いに隣接している保証はありません。そのため、それらを結合すると.join()
不自然な合成になる可能性があります。代わりに、を呼び出すコードでgetTextById()
、操作する文字列を選択する必要があります。
出力をテストします。
try {
var strings = getTextById("bio");
if (strings === null) {
// Do something.
} else if (strings.length === 1) {
// Do something with strings[0]
} else { // Could be another else if
// Do something. It all depends on the context.
}
} catch (e) {
console.log(e.message);
}
.trim()
内部にgetStringsFromChildren()
先頭と末尾の空白を取り除くために(または一連のスペースを長さ0の文字列(""
)に変換するために)追加できますが、どのようにしてすべてのアプリケーションがテキスト(文字列)に発生する必要があるかを事前に知ることができます見つかったら?わからないので、特定の実装に任せてgetStringsFromChildren()
、汎用的にしましょう。
このレベルの特異性(target
など)が不要な場合があります。すばらしい。そのような場合は、シンプルなソリューションを使用してください。ただし、一般化されたアルゴリズムを使用すると、単純な状況と複雑な状況に対応できます。
最初の#textノードのコンテンツを返すES6バージョン
const extract = (node) => {
const text = [...node.childNodes].find(child => child.nodeType === Node.TEXT_NODE);
return text && text.textContent.trim();
}
.from()
して、浅いコピーの配列インスタンスを作成する。(2)を使用して、.find()
を使用して文字列比較を行う.nodeName
。使用node.NodeType === Node.TEXT_NODE
する方が良いでしょう。(3)値がない場合に空の文字列を返すは、テキストノードが見つからnull
ない場合に真になります。テキストノードが見つからない場合は、作成する必要があります。空の文字列を返すと、テキストノードが存在し、正常に操作できるという誤った印象を与える可能性があります。本質的に、空の文字列を返すことは白い嘘であり、回避するのが最善です。""
[...node.childNodes]
に変換するために使用する方が良い
$('.title').clone() //clone the element
.children() //select all the children
.remove() //remove all the children
.end() //again go back to selected element
.text(); //get the text of element
a
要素内のテキストも取得します:jsfiddle.net/ekHJH
.
、あなたのセレクタの開始時に、あなたが実際のテキストを取得する意味title
を持つ要素ではなく、要素をclass="title"
.innerText
は、最近採用された古いIE規約です。標準のDOMスクリプティングに関してnode.nodeValue
は、テキストノードのテキストを取得する方法です。
これは空白も無視するため、コアJavascriptを使用して空のtextNodes..codeを取得することはありません。
var oDiv = document.getElementById("MyDiv");
var firstText = "";
for (var i = 0; i < oDiv.childNodes.length; i++) {
var curNode = oDiv.childNodes[i];
whitespace = /^\s*$/;
if (curNode.nodeName === "#text" && !(whitespace.test(curNode.nodeValue))) {
firstText = curNode.nodeValue;
break;
}
}
jsfiddleでそれを確認します- http://jsfiddle.net/webx/ZhLep/
curNode.nodeType === Node.TEXT_NODE
方が良いだろう。ループ内で文字列比較と正規表現を使用することは、特に規模がoDiv.childNodes.length
大きくなるため、パフォーマンスの低いソリューションです。このアルゴリズムはOPの特定の問題を解決しますが、恐ろしいパフォーマンスコストがかかる可能性があります。テキストノードの配置または数が変更された場合、このソリューションが正確な出力を返すことは保証できません。つまり、希望する正確なテキストノードをターゲットにすることはできません。あなたにはそこにテキストのHTML構造の慈悲と配置である。
これは、すべての子ノード(再帰的)の連結されたテキストを制限する文字列を作成する ES6での私のソリューションです。子ノードのshdowrootにもアクセスすることに注意してください。
function text_from(node) {
const extract = (node) => [...node.childNodes].reduce(
(acc, childnode) => [
...acc,
childnode.nodeType === Node.TEXT_NODE ? childnode.textContent.trim() : '',
...extract(childnode),
...(childnode.shadowRoot ? extract(childnode.shadowRoot) : [])],
[]);
return extract(node).filter(text => text.length).join('\n');
}
このソリューションは、https://stackoverflow.com/a/41051238./1300775のソリューションに触発されました。