[javascript] 자식 노드 인덱스 가져 오기

곧바로 자바 스크립트 (즉, jQuery 등과 같은 확장이 없음)에서 모든 자식 노드를 반복하고 비교하지 않고 부모 노드 내부의 자식 노드 인덱스를 결정하는 방법이 있습니까?

예 :

var child = document.getElementById('my_element');
var parent = child.parentNode;
var childNodes = parent.childNodes;
var count = childNodes.length;
var child_index;
for (var i = 0; i < count; ++i) {
  if (child === childNodes[i]) {
    child_index = i;
    break;
  }
}

자녀의 색인을 결정하는 더 좋은 방법이 있습니까?



답변

previousSibling속성을 사용하여 돌아올 때까지 형제를 반복하여 null몇 형제를 만났는지 계산할 수 있습니다.

var i = 0;
while( (child = child.previousSibling) != null )
  i++;
//at the end i will contain the index.

Java와 같은 언어에는 getPreviousSibling()함수가 있지만 JS에서는 속성이되었습니다 previousSibling.


답변

나는 이것을 사용 indexOf하는 것을 좋아하게되었습니다 . 때문에 indexOfArray.prototypeparent.children이다 NodeList, 당신은 사용할 필요가 call();그것은 종류의 추한의이다 그러나 어떤 자바 스크립트 데브는 어쨌든 잘 알고 있어야하는 하나의 라이너를 사용하는 기능을합니다.

var child = document.getElementById('my_element');
var parent = child.parentNode;
// The equivalent of parent.children.indexOf(child)
var index = Array.prototype.indexOf.call(parent.children, child);


답변

ES6 :

Array.from(element.parentNode.children).indexOf(element)

설명 :

  • element.parentNode.childrenelement해당 요소를 포함하여 의 형제를 반환합니다 .

  • Array.from→이의 생성자를 캐스트 childrenArray객체

  • indexOf→ 이제 개체 indexOf가 있으므로 신청할 수 있습니다 Array.


답변

ES— 짧게

[...element.parentNode.children].indexOf(element);

스프레드 연산자는이를위한 지름길입니다.


답변

(안전을 위해 접두어가 붙은) 요소 추가 .getParentIndex () :

Element.prototype.PREFIXgetParentIndex = function() {
  return Array.prototype.indexOf.call(this.parentNode.children, this);
}


답변

모든 자식이 문서에서 순서대로 정렬 된 요소가 주어진 경우 가장 빠른 방법은 요소의 문서 위치를 비교하여 이진 검색을 수행하는 것입니다. 그러나 결론에서 소개 한 가설은 기각됩니다. 요소가 많을수록 성능 잠재력이 커집니다. 예를 들어, 256 개의 요소가있는 경우 (최적 적으로) 16 개만 확인하면됩니다! 65536의 경우 256 개만! 성능은 2의 힘으로 성장합니다! 더 많은 숫자 / 통계를보십시오. Wikipedia 방문

(function(constructor){
   'use strict';
    Object.defineProperty(constructor.prototype, 'parentIndex', {
      get: function() {
        var searchParent = this.parentElement;
        if (!searchParent) return -1;
        var searchArray = searchParent.children,
            thisOffset = this.offsetTop,
            stop = searchArray.length,
            p = 0,
            delta = 0;

        while (searchArray[p] !== this) {
            if (searchArray[p] > this)
                stop = p + 1, p -= delta;
            delta = (stop - p) >>> 1;
            p += delta;
        }

        return p;
      }
    });
})(window.Element || Node);

그런 다음 사용하는 방법은 모든 요소의 ‘parentIndex’속성을 가져 오는 것입니다. 예를 들어 다음 데모를 확인하십시오.

(function(constructor){
   'use strict';
    Object.defineProperty(constructor.prototype, 'parentIndex', {
      get: function() {
        var searchParent = this.parentNode;
        if (searchParent === null) return -1;
        var childElements = searchParent.children,
            lo = -1, mi, hi = childElements.length;
        while (1 + lo !== hi) {
            mi = (hi + lo) >> 1;
            if (!(this.compareDocumentPosition(childElements[mi]) & 0x2)) {
                hi = mi;
                continue;
            }
            lo = mi;
        }
        return childElements[hi] === this ? hi : -1;
      }
    });
})(window.Element || Node);

output.textContent = document.body.parentIndex;
output2.textContent = document.documentElement.parentIndex;
Body parentIndex is <b id="output"></b><br />
documentElements parentIndex is <b id="output2"></b>

한계

  • 이 솔루션 구현은 IE8 이하에서는 작동하지 않습니다.

이진 VS 선형 검색 20 만 요소에서 (일부 모바일 브라우저가 충돌 할 수 있습니다.주의!) :

  • 이 테스트에서는 선형 검색이 중간 요소와 이진 검색을 찾는 데 걸리는 시간을 확인합니다. 왜 중간 요소입니까? 다른 모든 위치의 평균 위치에 있기 때문에 가능한 모든 위치를 가장 잘 나타냅니다.

이진 검색

코드 스 니펫 표시

역방향 (`lastIndexOf`) 선형 검색

앞으로 (`indexOf`) 선형 검색

PreviousElementSibling 카운터 검색

parentIndex를 가져 오기 위해 PreviousElementSiblings의 수를 계산합니다.

검색 안함

브라우저가 검색을 최적화하면 테스트 결과가 어떻게 될지 벤치마킹하기 위해.

Conculsion

그러나 Chrome에서 결과를 본 후 결과는 예상했던 것과 반대입니다. Dumber forwards 선형 검색은 이진 검색보다 빠른 187ms (3850 %)였습니다. 분명히 Chrome은 어떻게 든 마술 적으로 능가 console.assert하고 최적화하거나 (보다 낙관적으로) Chrome 내부적으로 DOM에 숫자 색인 시스템을 사용하고이 내부 색인 시스템은 객체에서 Array.prototype.indexOf사용될 때 적용되는 최적화를 통해 노출됩니다 HTMLCollection.


답변

노드에 많은 형제가있을 때 이진 검색 알고리즘 을 사용 하여 성능을 향상시킵니다.

function getChildrenIndex(ele){
    //IE use Element.sourceIndex
    if(ele.sourceIndex){
        var eles = ele.parentNode.children;
        var low = 0, high = eles.length-1, mid = 0;
        var esi = ele.sourceIndex, nsi;
        //use binary search algorithm
        while (low <= high) {
            mid = (low + high) >> 1;
            nsi = eles[mid].sourceIndex;
            if (nsi > esi) {
                high = mid - 1;
            } else if (nsi < esi) {
                low = mid + 1;
            } else {
                return mid;
            }
        }
    }
    //other browsers
    var i=0;
    while(ele = ele.previousElementSibling){
        i++;
    }
    return i;
}