답변:
var text = $(".title").contents().filter(function() {
return this.nodeType == Node.TEXT_NODE;
}).text();
contents선택한 요소를 가져 와서 필터 기능을 적용합니다. 필터 함수는 텍스트 노드 (예 :가있는 노드 nodeType == Node.TEXT_NODE) 만 반환합니다 .
text()하기 때문에 필요 filter합니다.
jQuery("*").each(function() { console.log(this.nodeType); })얻었습니다 .
다음을 사용하여 첫 번째 childNode의 nodeValue를 얻을 수 있습니다.
$('.title')[0].childNodes[0].nodeValue
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(? - 어떤 노드가 3 번이 숫자 비교가 빠른하지만 curNode.nodeType == 3 읽을 수 없습니다)
curNode.NodeType === Node.TEXT_NODE. 이 비교는 알려지지 않은 가능한 반복 루프 내에서 발생합니다. 두 개의 작은 숫자를 비교하는 것이 다양한 길이의 문자열을 비교하는 것보다 낫습니다 (시간 및 공간 고려 사항). 이 상황에서 올바른 질문은 "내가 가지고있는 노드의 종류 / 유형"이 아니라 "내 이름이 무엇입니까?"입니다. developer.mozilla.org/en-US/docs/Web/API/Node/nodeType
childNodes하려는 경우 요소 노드가 둘 이상의 텍스트 노드를 가질 수 있음을 알아야 합니다. 일반 솔루션에서는 대상으로 지정할 요소 노드 내에서 텍스트 노드의 인스턴스 (첫 번째, 두 번째, 세 번째 등)를 지정해야 할 수 있습니다.
"복잡"하거나 깊게 중첩 된 요소에 유용 할 수있는 또 다른 기본 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. 둘 사이의 차이점은 NodeIterator단순한 선형 반복기이며 TreeWalker형제 및 조상을 통해 탐색 할 수도 있다는 것입니다.
우선, DOM에서 텍스트를 찾을 때 항상 이것을 명심하십시오.
이 문제는 XML / HTML의 구조에주의를 기울이게합니다.
이 순수한 JavaScript 예제에서는 다른 종류의 노드와 인터리브 될 수있는 여러 텍스트 노드 의 가능성을 설명합니다 . 그러나 처음에는 공백에 대한 판단을 내리지 않고 필터링 작업을 다른 코드에 맡깁니다.
이 버전에서는 NodeList호출 / 클라이언트 코드에서 전달합니다 .
/**
* 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()두 개의 도우미 기능을 사용 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.
}
다음으로 반환 값 (Array 또는 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에서는 두 개의 텍스트 노드가 존재하며 둘 다 ( )를 getStringFromChildren()반환합니다 . 그러나 정규식을 사용하여 순수한 공백 문자 행을 필터링합니다..nodeValue"\n"filterWhitespaceLines()
null개행 문자 ( "\n") 대신 반환하는 것이 클라이언트 / 호출 코드에 거짓말을하는 형태입니까? 인간적인 측면에서는 그렇지 않습니다. DOM 측면에서 그렇습니다. 그러나 여기서 문제는 텍스트를 편집하는 것이 아니라 텍스트를받는 것입니다. 호출 코드로 반환 할 사람 텍스트가 없습니다.
누군가의 HTML에 얼마나 많은 개행 문자가 나타날 수 있는지 결코 알 수 없습니다. "두 번째"줄 바꿈 문자를 찾는 카운터를 만드는 것은 신뢰할 수 없습니다. 존재하지 않을 수 있습니다.
물론 추가 공백이 있는 빈 요소 (예 2) 에서 텍스트 를 편집 하는 문제 <p></p>는 단락의 태그 사이에있는 텍스트 노드 하나를 제외한 모든 요소를 제거 (건너 뛰기)하여 요소에 정확한 내용이 포함되도록 할 수 있습니다. 표시해야합니다.
어쨌든, 당신이 특별한 일을하는 경우를 제외하고, 어떤 텍스트 노드의 .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."]
이 두 문자열이 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()일반화하십시오.
이 수준의 특이성 (the targetand such)이 필요하지 않은 경우가 있을 수 있습니다 . 그거 좋네. 이 경우 간단한 해결책을 사용하십시오. 그러나 일반화 된 알고리즘을 사용하면 간단하고 복잡한 상황을 수용 할 수 있습니다.
첫 번째 #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]변환에 HTMLCollection 배열로
$('.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를 사용하여 Blank 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 솔루션에서 영감을 받았습니다 .