자식 노드를 얻는 가장 좋은 방법


233

JavaScript는 모든 요소에서 첫 번째 자식 요소를 가져 오는 다양한 방법을 제공하지만 궁금합니다. 가장 좋은 것은, 브라우저와 호환 가능하고, 가장 빠르고, 포괄적이며 예측 가능한 동작입니다. 별명으로 사용하는 메소드 / 속성 목록 :

var elem = document.getElementById('container');
var child = elem.children[0];
var child = elem.firstElementChild; // == children[0]

이것은 두 경우 모두에 적용됩니다.

var child = elem.childNodes[0]; // or childNodes[1], see below

그것은 형태의 경우이거나 <div> 반복의 . 텍스트 요소가 발생할 수있는 경우 :

var child = elem.childNodes; // treat as NodeList
var child = elem.firstChild;

지금까지 내가 해결할 수로, firstChild로부터 NodeList를 사용 childNodes하고, firstElementChild용도를children . 나는 MDN 참조를 바탕으로이 가정을하고있다 :

childNode 요소 노드의 첫 번째 자식 요소에 대한 참조이거나 null 없는 경우입니다.

나는 속도면에서 차이가 있다면 아무것도 옆에 없을 것이라고 추측하고 있습니다. firstElementChild 효과적으로에 대한 참조입니다 children[0], 그리고 children객체 어쨌든 이미 메모리에.

나를 던지는 것은 childNodes물건입니다. 테이블 요소에서 양식을 살펴보기 위해 사용했습니다. children모든 양식 요소를 나열 하지만 childNodesHTML 코드의 공백을 포함하는 것으로 보입니다.

console.log(elem.childNodes[0]);
console.log(elem.firstChild);

두 로그 <TextNode textContent="\n ">

console.log(elem.childNodes[1]);
console.log(elem.children[0]);
console.log(elem.firstElementChild);

모든 로그 <input type="text"> . 어떻게 오세요? 한 객체가 "원시"HTML 코드를 사용하여 작업 할 수 있지만 다른 객체는 DOM을 사용하지만 childNodes요소는 두 레벨에서 모두 작동하는 것으로 보입니다.

내 초기 질문으로 돌아가려면 내 추측은 다음과 같습니다. 가장 포괄적 인 객체를 원한다면 childNodes 갈 길입니다.하지만 포괄적이기 때문에 원하는 요소를 반환하는 측면에서 가장 예측하기 쉽지 않을 수 있습니다. 주어진 순간에 기대하십시오. 이 경우 크로스 브라우저 지원도 문제가 될 수 있지만 내가 틀릴 수 있습니다.

누구나 가까이에있는 물건들 사이의 구별을 분명히 할 수 있습니까? 무시할만한 속도 차이가 있다면, 알고 싶습니다. 내가이 모든 것을 잘못 본다면, 저에게 교육을 주시기 바랍니다.


추신 : 제발, 제발, JavaScript를 좋아합니다. 예, 이런 종류의 일을 처리하고 싶습니다. "jQuery가이 문제를 해결합니다"와 같은 답변은 내가 찾는 것이 아니므로 아니요 꼬리표.


49
>> 제발 제발 제발 JavaScript를 좋아해서 이런 종류의 일을 처리하고 싶습니다. '당신이와 jQuery를 거래'와 같은 대답을 나는이에 대한 << upvotes을 찾고 있어요되지 않은 것
david.barkhuizen

답변:


211

당신이 그것을 너무 생각하고있는 것 같습니다. childNodes와 사이의 차이를 관찰했습니다. 공백으로 만 구성된 텍스트 노드를 포함하여 모든 노드 childrenchildNodes포함되어 있습니다.children 요소 만 자식 노드의 모음입니다. 그게 전부입니다.

알고 있어야 할 몇 가지 문제가 있지만 두 컬렉션에 대해 예측할 수있는 것은 없습니다.

  • IE <= 8은 공백 전용 텍스트 노드를 포함하지 않지만 childNodes다른 브라우저는 포함합니다
  • IE <= 8에는 주석 노드가 포함되어 children있지만 다른 브라우저에는 요소 만 있습니다.

children, firstElementChild친구는 편의상 요소로 제한되는 DOM에 대한 필터링 된보기를 제공합니다.


한 가지 여전히 나에게 버그가 있지만, childNodes가 선택하는 공백 텍스트 노드는 실제로 코드의 새로운 줄과 두 개의 탭입니다. 이것은 XHTML doctype 때문입니까? 태그 안에 코드를 구성하기 위해 공백을 넣어서 해결할 수 있습니까?
Elias Van Ootegem

@ ElliasVanOotegem : 그것은 doctype과 관련이 없습니다. 공백 텍스트 노드는 소스와 소스에 관계없이 HTML 및 XHTML 모두에 대해 DOM (IE <9 제외)에 항상 포함됩니다. 준비가되어 있지 않으면 잡을 수 있지만 일반적으로 좋은 일입니다.
Tim Down

이런 식으로 내 마크 업을 작성하는 것이 도움이되는지 의미했습니다 <td\n\t>content</td>. XML에서와 마찬가지로 과도한 공백이 데이터의 일부로 간주되지 않도록합니다 (이 경우 DOM). 태그 안에 공백이 DOM에 포함되는 이유는 무엇입니까?
Elias Van Ootegem

@EliasVanOotegem : 아, 알겠습니다. 태그 안의 태그 이름 뒤의 공백은 무시되므로 이런 종류의 작업을 수행 할 수 있습니다. 브라우저가 특정 요소 사이의 공백에 작은 간격을 추가하는 것을 방지하기 위해 정확한 레이아웃에 사용되는 기술을 보았습니다.
Tim Down

2
@Christophe : 아, 페어 포인트, 감사합니다. 답변에 메모를 추가하겠습니다. children표준이되거나 다른 브라우저에서 채택되기 10 년 전에 IE 4에서 시작된 것을 고려하면 IE <= 8이 정확하고 다른 브라우저가 잘못되었다고 주장 할 수 있습니다.
Tim Down

23

firstElementChild는 IE <9에서 사용할 수 없습니다 (firstChild 만 해당)

IE <9에서는 MS DOM (IE <9)이 빈 텍스트 노드를 저장하지 않기 때문에 firstChild는 firstElementChild입니다. 그러나 다른 브라우저에서 그렇게하면 빈 텍스트 노드가 반환됩니다 ...

내 솔루션

child=(elem.firstElementChild||elem.firstChild)

이것은 IE <9에서도 첫 번째 자식을 줄 것입니다.


elem.firstChild요소 노드가 아닌 경우 elem.firstElementChild항상 요소 노드 이므로 이전 IE에서는 결과가 다릅니다 .
duri

죄송하지만 모든 주요 브라우저에서 첫 번째 자녀를 얻는 방법을 알고 있습니다. 내가 알고 싶은 것은 서로 다른 유사점과 차이점을 더 잘 이해하기 위해 다른 대상을 구성하는 방법입니다. 나는 명확하게 나중에 내 질문을 수정거야, 미안 호환 문제에 대한
엘리아스 반 Ootegem

1
firstElementChildIE가 아닌 브라우저에서도 반드시 안전한 것은 아닙니다. Firefox는 3.5 버전에서만 지원하기 시작했습니다.
Tim Down

이것은 크롬, IE9 및 IE8에서 작동합니다 .firstElementChild가 있으면 다른 검사가 실행되지 않으므로 그렇지 않으면 (오래된 IE) firstChild가 있고 firstElementChild가없는 브라우저의 요소 노드입니다 (IE <9 ) ... 여전히 FF에 대해 궁금합니다
neu-rah

1
Tim은 정확합니다. 제가이 물건에 대해 인터넷 검색을 할 때 이것이 나타났습니다. 한 번에 한 번 확인하기에 좋은 사이트입니다.
Elias Van Ootegem

20

크로스 브라우저 방법은을 사용 childNodes하여 ELEMENT_NODE 를 사용 하여 NodeList모든 노드의 배열을 만드는 것 입니다.nodeType

/**
 * Return direct children elements.
 *
 * @param {HTMLElement}
 * @return {Array}
 */
function elementChildren (element) {
    var childNodes = element.childNodes,
        children = [],
        i = childNodes.length;

    while (i--) {
        if (childNodes[i].nodeType == 1) {
            children.unshift(childNodes[i]);
        }
    }

    return children;
}

http://jsfiddle.net/s4kxnahu/

lodash 와 같은 유틸리티 라이브러리를 사용하는 경우 특히 쉽습니다 .

/**
 * Return direct children elements.
 *
 * @param {HTMLElement}
 * @return {Array}
 */
function elementChildren (element) {
    return _.where(element.childNodes, {nodeType: 1});
}

미래:

의사 클래스 querySelectorAll와 함께 사용할 수 있습니다 :scope(선택기의 참조 점 인 요소와 일치).

parentElement.querySelectorAll(':scope > *');

작성 당시에는 Chrome, Firefox 및 Safari에서 :scope지원 됩니다.


: scope가 사양에서 제거되었습니다 . 미래 섹션 을 제거해야합니까 ?
Thomas Marti

4

다른 답변에 덧붙여서, 특히 <svg>요소를 다룰 때 특히 주목할만한 차이점이 있습니다 .

나는 모두를 사용하고 있습니다 .childNodes.children및 작업 선호 HTMLCollection에 의해 전달 .children게터.

그러나 오늘은에서 사용할 때 IE / Edge에 문제가 발생 .children했습니다 <svg>. .children기본 HTML 요소에서는 IE에서 지원 되지만 문서 / 문서 조각 또는 SVG 요소 에서는 지원되지 않습니다 .

나를 위해, .childNodes[n]걱정할 텍스트 노드가 없기 때문에 필요한 요소를 간단히 잡을 수있었습니다 . 동일한 작업을 수행 할 수 있지만 위에서 언급 한 것처럼 예기치 않은 요소가 발생할 수 있습니다.

이것이 .children현대의 IE에서 js의 다른 곳에서 작동하고 문서 또는 SVG 요소에서 실패 하는 이유를 알아 내려고 노력하는 누군가에게 도움이 되기를 바랍니다.


3

이봐, 당신은 공백이 당신을 바보 못하게합니다. 콘솔 브라우저에서 이것을 테스트하십시오. 기본 자바 스크립트를 사용하십시오. 다음은 동일한 클래스를 가진 두 개의 'ul'세트가있는 예입니다. 공백을 피하기 위해 'ul'목록을 모두 한 줄로 가질 필요는 없습니다. 공백을 뛰어 넘기 위해 배열 수를 사용하십시오.

js 바이올린 링크로 공백 querySelector()childNodes[]피하는 방법 : https://jsfiddle.net/aparadise/56njekdo/

var y = document.querySelector('.list');
var myNode = y.childNodes[11].style.backgroundColor='red';

<ul class="list">
    <li>8</li>
    <li>9</li>
    <li>100</li>
</ul>

<ul class="list">
    <li>ABC</li>
    <li>DEF</li>
    <li>XYZ</li>
</ul>

내 투표는 아니지만, 다음과 같은 이유로 누군가 투표를하지 않은 것으로 생각 document.querySelector합니다. b) 문제는 기본적으로 내부childrenchildNodes 내부 의 차이점이 무엇인지 묻는 것 입니다. c는) 때문에, 질문에 demonstraded 같이 childNodes 않는 공백 노드를 포함 children하지 않습니다 ...
엘리아스 반 Ootegem
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.