चाइल्ड नोड इंडेक्स प्राप्त करें


125

सीधे जावास्क्रिप्ट में (जैसे, कोई एक्सटेंशन जैसे कि 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;
  }
}

क्या बच्चे के सूचकांक को निर्धारित करने का एक बेहतर तरीका है?


2
क्षमा करें, क्या मैं पूरी तरह से मूर्ख हूं? यहां बहुत सारे सीखे हुए उत्तर दिए गए हैं, लेकिन सभी बच्चों को प्राप्त करने के लिए आपको नोड्स की आवश्यकता नहीं है parent.childNodes, बल्कि parent.children। उत्तरार्द्ध केवल Elementsविशेष Textनोड्स को छोड़कर, लिस्ट करता है ... यहां दिए गए कुछ उत्तर, जैसे कि उपयोग कर previousSiblingरहे हैं, सभी चाइल्ड नोड्स का उपयोग करने पर आधारित हैं, जबकि अन्य केवल उन बच्चों से परेशान हैं जो Elementएस ... (!)
माइक कृंतक

@mikerodent मुझे याद नहीं है कि मेरा उद्देश्य क्या था जब मैंने शुरू में यह सवाल पूछा था, लेकिन यह एक महत्वपूर्ण विवरण है जो मुझे पता नहीं था। जब तक आप सावधान रहें, .childNodesइसके बजाय निश्चित रूप से उपयोग किया जाना चाहिए .children। जैसा कि आपने बताया, शीर्ष 2 पोस्ट किए गए उत्तर अलग-अलग परिणाम देंगे।
सभी श्रमिक

जब 1000 से अधिक नोड्स के हजारों लुकअप करने की योजना बना रहे हैं, तो नोड को जानकारी संलग्न करें (जैसे कि child.dataset के माध्यम से)। लक्ष्य O (n) या O (n ^ 2) एल्गोरिथम को O (1) एल्गोरिथम में बदलना होगा। नकारात्मक पक्ष यह है कि यदि नोड्स को नियमित रूप से जोड़ा और हटाया जाता है, तो नोड्स से जुड़ी संबंधित स्थिति की जानकारी को भी अपडेट करना होगा, जिसके परिणामस्वरूप कोई भी प्रदर्शन लाभ नहीं होगा। सामयिक पुनरावृत्ति एक बड़ा सौदा नहीं है (उदाहरण के लिए क्लिक हैंडलर) लेकिन दोहराया पुनरावृत्ति समस्याग्रस्त है (उदाहरण के लिए मूसमव)।
क्यूबिकलसॉफ्ट

जवाबों:


122

आप previousSiblingभाई-बहनों के माध्यम से वापस पाने के लिए संपत्ति का उपयोग कर सकते हैं जब तक आप वापस नहीं आते हैं nullऔर गिनते हैं कि आपके कितने भाई-बहन हैं:

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

कृपया ध्यान दें कि जावा जैसी भाषाओं में, एक getPreviousSibling()फ़ंक्शन है, हालांकि जेएस में यह एक संपत्ति बन गई है - previousSibling


2
हां। आपने पाठ में एक getPrepretSibling () छोड़ दिया है।
टिम डाउन

7
इस दृष्टिकोण को बाल सूचकांक निर्धारित करने के लिए समान संख्या में पुनरावृत्तियों की आवश्यकता होती है, इसलिए मैं यह नहीं देख सकता कि यह कितना तेज़ होगा।
माइकल

31
एक पंक्ति संस्करण:for (var i=0; (node=node.previousSibling); i++);
स्कॉट मील्स

2
@sfarbota जावास्क्रिप्ट ब्लॉक स्कोपिंग को नहीं जानता है, इसलिए iयह प्रशंसनीय होगा।
A1rPun

3
@nepdev कि .previousSiblingऔर के बीच के अंतर के कारण होगा .previousElementSibling। पूर्व हिट पाठ नोड्स, बाद नहीं है।
अबुलेजेली

133

मुझे इसके indexOfलिए उपयोग करने का शौक है । क्योंकि indexOfचालू है Array.prototypeऔर parent.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);

7
var index = [] .indexOf.call (child.parentNode.children, child);
17

23
Fwiw, का उपयोग करके []हर बार उस कोड को चलाने के लिए एक ऐरे उदाहरण बनाता है, जो मेमोरी और GC बनाम उपयोग के लिए कम कुशल है Array.prototype
स्कॉट मील्स

@ScottMiles क्या मैं आपको कुछ और बताने के लिए कह सकता हूँ? []कचरा मूल्य के रूप में स्मृति पर साफ नहीं मिलता है?
मृगईहा

14
[].indexOfइंजन का मूल्यांकन करने के लिए केवल indexOfप्रोटोटाइप पर कार्यान्वयन तक पहुंचने के लिए एक सरणी उदाहरण बनाना होगा । उदाहरण ही अप्रयुक्त हो जाता है (यह जीसी करता है, यह रिसाव नहीं है, यह सिर्फ चक्र बर्बाद कर रहा है)। Array.prototype.indexOfअनाम उदाहरण आवंटित किए बिना सीधे उस कार्यान्वयन तक पहुँचता है। अंतर लगभग सभी परिस्थितियों में नगण्य होने वाला है, इसलिए स्पष्ट रूप से यह ध्यान रखने योग्य नहीं है।
स्कॉट मील्स

3
IE में त्रुटि से सावधान रहें! इंटरनेट एक्सप्लोरर 6, 7 और 8 ने इसका समर्थन किया, लेकिन गलत तरीके से टिप्पणी नोड्स शामिल हैं। स्रोत " डेवलपर.
mozilla.org/en-US/docs/Web/API/ParentNode/…

102

ES6:

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

स्पष्टीकरण:

  • element.parentNode.childrenelementउस तत्व सहित, के भाइयों को लौटाता है ।

  • Array.fromchildrenकिसी Arrayवस्तु के निर्माता कास्ट करता है

  • indexOf→ आप आवेदन कर सकते हैं indexOfक्योंकि अब आपके पास एक Arrayवस्तु है।


2
सबसे सुंदर समाधान, दूर से :)
अमित सक्सेना

1
लेकिन केवल क्रोम 45 और फ़ायरफ़ॉक्स 32 से उपलब्ध है, और इंटरनेट एक्सप्लोरर पर बिल्कुल भी उपलब्ध नहीं है।
पीटर

इंटरनेट एक्सप्लोरर अभी भी जीवित है? बस जॉक .. ठीक है, ताकि आप एक की जरूरत है polyfill बनाने के लिए Array.fromइंटरनेट एक्सप्लोरर पर काम करता है
Abdennour Toumi

9
MDN के अनुसार, Array.from () कॉलिंग creates a new Array instance from an array-like or iterable object.एक इंडेक्स खोजने के लिए एक नया ऐरे इंस्टेंस बनाना मेमोरी या GC कुशल नहीं हो सकता है, यह इस बात पर निर्भर करता है कि किस ऑपरेशन में, किस मामले में, जैसा कि स्वीकृत उत्तर में समझाया गया है, अधिक होगा। आदर्श।
TheDarkIn1978

1
@ TheDarkIn1978 मुझे पता है कि कोड लालित्य और ऐप के प्रदर्शन के बीच एक ट्रेड-ऑफ है UM
अब्देनौर टुमी

38

ES-छोटे

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

प्रसार ऑपरेटर उसके लिए एक शॉर्टकट है


यह एक दिलचस्प ऑपरेटर है।
सभी कार्यकर्ता आवश्यक

बीच क्या अंतर है e.parentElement.childNodesऔर e.parentNode.children?
mesqueeb

4
childNodesपाठ नोड्स के रूप में अच्छी तरह से शामिल है
फिलिप

टाइपस्क्रिप्ट के साथ आपको मिलता है Type 'NodeListOf<ChildNode>' must have a '[Symbol.iterator]()' method that returns an iterator.ts(2488)
ZenVentzi

9

सुरक्षा के लिए एक उपसर्ग जोड़ रहा है। element.getParentIndex ():

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

1
वेब विकास की पीड़ा का एक कारण है: उपसर्ग-उछल देव। सिर्फ क्यों नहीं if (!Element.prototype.getParentIndex) Element.prototype.getParentIndex = function(){ /* code here */ }? वैसे भी, अगर भविष्य में इसे कभी मानक के रूप में लागू किया जाता है, तो इसे संभवतः एक गेटर की तरह लागू किया जाएगा element.parentIndex। तो, मैं कहूंगा कि सबसे अच्छा तरीका होगाif(!Element.prototype.getParentIndex) Element.prototype.getParentIndex=Element.prototype.parentIndex?function() {return this.parentIndex}:function() {return Array.prototype.indexOf.call(this.parentNode.children, this)}
जैक गिफिन

3
क्योंकि भविष्य में getParentIndex()आपके कार्यान्वयन से भिन्न हस्ताक्षर हो सकते हैं।
मिकमेकाना

7

मैं परिकल्पना करता हूं जिसने एक तत्व दिया है जहां उसके सभी बच्चों को क्रमिक रूप से दस्तावेज़ पर आदेश दिया गया है, सबसे तेज़ तरीका द्विआधारी खोज करना चाहिए, तत्वों के दस्तावेज़ पदों की तुलना करना। हालांकि, निष्कर्ष में पेश की गई परिकल्पना को खारिज कर दिया गया है। आपके पास जितने अधिक तत्व होंगे, प्रदर्शन की क्षमता उतनी ही अधिक होगी। उदाहरण के लिए, यदि आपके पास 256 तत्व थे, तो (आशावादी) आपको केवल उनमें से 16 की जांच करनी होगी! 65536 के लिए, केवल 256! प्रदर्शन 2 की शक्ति तक बढ़ता है! अधिक संख्या / आंकड़े देखें। विकिपीडिया पर जाएँ

(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);

फिर, जिस तरह से आप इसका उपयोग करते हैं, वह किसी भी तत्व की 'पैरेंटइन्डेक्स' संपत्ति प्राप्त करने से होता है। उदाहरण के लिए, निम्नलिखित डेमो देखें।

(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 और उसके नीचे काम नहीं करेगा।

बाइनरी वीएस रैखिक खोज 200 हजार तत्वों पर (कुछ मोबाइल ब्राउज़रों को नष्ट कर सकता है, बीवेयर!):

  • इस परीक्षण में, हम देखेंगे कि एक रैखिक खोज के लिए मध्य तत्व वी.एस. को एक द्विआधारी खोज खोजने में कितना समय लगता है। मध्य तत्व क्यों? क्योंकि यह अन्य सभी स्थानों के औसत स्थान पर है, इसलिए यह सभी संभावित स्थानों का सबसे अच्छा प्रतिनिधित्व करता है।

द्विआधारी खोज

पीछे की ओर (`lastIndexOf`) रैखिक खोज

आगे की ओर (`indexOf`) रैखिक खोज

पिछला ई-आधार खोज काउंटर खोज

पेरेंटइंडेक्स प्राप्त करने के लिए पिछले ई-कॉमर्स की संख्या की गणना करता है।

कोई खोज नहीं

बेंचमार्किंग के लिए यदि ब्राउज़र खोज को अनुकूलित करता है तो परीक्षण का परिणाम क्या होगा।

द कंक्लूज़न

हालाँकि, क्रोम में परिणाम देखने के बाद, परिणाम वही हैं जो अपेक्षित था। द्विआधारी खोज की तुलना में डम्बर फॉरवर्ड रैखिक खोज एक आश्चर्यजनक 187 एमएस, 3850% थी। जाहिर है, क्रोम ने किसी तरह जादुई रूप से console.assertइसे आउटसोर्स किया और इसे दूर अनुकूलित किया, या (अधिक आशावादी रूप से) क्रोम आंतरिक रूप से डोम के लिए संख्यात्मक अनुक्रमण प्रणाली का उपयोग करता है, और यह आंतरिक अनुक्रमण प्रणाली Array.prototype.indexOfकिसी HTMLCollectionवस्तु पर उपयोग किए जाने वाले अनुकूलन के माध्यम से उजागर होती है ।


कुशल, लेकिन अव्यावहारिक।
Applemonkey496

3

जब बड़ी मात्रा में भाई-बहन होते हैं, तो प्रदर्शन को बेहतर बनाने के लिए द्विआधारी खोज एल्गोरिथ्म का उपयोग करें ।

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;
}

काम नहीं करता है। मैं यह इंगित करने के लिए मजबूर हूं कि IE संस्करण और "अन्य ब्राउज़र" संस्करण विभिन्न परिणामों की गणना करेगा। "अन्य ब्राउज़र" तकनीक अपेक्षा के अनुसार काम करती है, मूल नोड के तहत nth स्थिति प्राप्त करना, हालांकि IE तकनीक "स्रोत के क्रम में वस्तु की क्रमिक स्थिति को पुनः प्राप्त करती है, जैसा कि दस्तावेज़ के सभी संग्रह में ऑब्जेक्ट दिखाई देता है" ( msdn.microsoft) .com / en-gb / पुस्तकालय / / / ms534635 (v = बनाम 85) .aspx )। उदाहरण के लिए, मुझे "IE" तकनीक का उपयोग करके 126 मिला, और फिर दूसरे का उपयोग करके 4।
क्रिस्टोफर बुल

1

मेरे पास पाठ नोड्स के साथ समस्या थी, और यह गलत सूचकांक दिखा रहा था। इसे ठीक करने के लिए यहाँ संस्करण है।

function getChildNodeIndex(elem)
{   
    let position = 0;
    while ((elem = elem.previousSibling) != null)
    {
        if(elem.nodeType != Node.TEXT_NODE)
            position++;
    }

    return position;
}

0
Object.defineProperties(Element.prototype,{
group : {
    value: function (str, context) {
        // str is valid css selector like :not([attr_name]) or .class_name
        var t = "to_select_siblings___";
        var parent = context ? context : this.parentNode;
        parent.setAttribute(t, '');
        var rez = document.querySelectorAll("[" + t + "] " + (context ? '' : ">") + this.nodeName + (str || "")).toArray();
        parent.removeAttribute(t);            
        return rez;  
    }
},
siblings: {
    value: function (str, context) {
        var rez=this.group(str,context);
        rez.splice(rez.indexOf(this), 1);
        return rez; 
    }
},
nth: {  
    value: function(str,context){
       return this.group(str,context).indexOf(this);
    }
}
}

भूतपूर्व

/* html */
<ul id="the_ul">   <li></li> ....<li><li>....<li></li>   </ul>

 /*js*/
 the_ul.addEventListener("click",
    function(ev){
       var foo=ev.target;
       foo.setAttribute("active",true);
       foo.siblings().map(function(elm){elm.removeAttribute("active")});
       alert("a click on li" + foo.nth());
     });

1
क्या आप बता सकते हैं कि आप क्यों बढ़ाते हैं Element.prototype? फ़ंक्शंस उपयोगी दिखते हैं, लेकिन मुझे नहीं पता कि ये फ़ंक्शंस क्या करते हैं (भले ही नमाज़ स्पष्ट हो)।
A1rPun 19

@ Element_prototype का विस्तार करें इसका कारण समानता है ... 4 पूर्व elemen.children, element.parentNode आदि ... तो उसी तरह जब आप element.siblings को संबोधित करते हैं .... समूह विधि थोड़ा जटिल कारण है जिसे मैं विस्तारित करना चाहता हूं। एक ही नोड के द्वारा समान रूप से ग्यारहवें हिस्से के लिए एक छोटा सिबलिंग दृष्टिकोण और समान गुण होने पर भी एक ही पूर्वज नहीं है
बोरट्यूनैक

मुझे पता है कि प्रोटोटाइप का विस्तार क्या है, लेकिन मुझे यह जानना पसंद है कि आपके कोड का उपयोग कैसे किया जाता है। el.group.value()??। आपके उत्तर की गुणवत्ता में सुधार करने के लिए मेरी पहली टिप्पणी है।
A1rPun

समूह और भाई-बहन के तरीके स्थापित डोम तत्वों के साथ ऐरे को वापस करते हैं। .... आपकी टिप्पणी के लिए धन्यवाद और टिप्पणी के कारण के लिए
bortunac

बहुत सुरुचिपूर्ण, फिर भी बहुत धीमी गति से।
जैक गिफिन


-1
<body>
    <section>
        <section onclick="childIndex(this)">child a</section>
        <section onclick="childIndex(this)">child b</section>
        <section onclick="childIndex(this)">child c</section>
    </section>
    <script>
        function childIndex(e){
            let i = 0;
            while (e.parentNode.children[i] != e) i++;
            alert('child index '+i);
        }
    </script>
</body>

आपको यहां jQuery की आवश्यकता नहीं है।
विटाली ज़ेडेनविच
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.