চাইল্ড নোড সূচক পান


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গুলি ... (!)
মাইক করাল

@ মাইক্রোডেন্ট আমি মনে করি না আমার উদ্দেশ্যটি কী ছিল যখন আমি প্রথমদিকে এই প্রশ্নটি জিজ্ঞাসা করি, তবে এটি একটি মূল বিবরণ যা সম্পর্কে আমি অবগত ছিল না। আপনি সাবধান না .childNodesহলে অবশ্যই এর পরিবর্তে ব্যবহার করা উচিত .children। শীর্ষস্থানীয় 2 টি পোস্ট করা উত্তরগুলি আপনি নির্দেশিত হিসাবে বিভিন্ন ফলাফল দেবে।
সমস্ত কর্মী

1000+ নোডের উপরে হাজার হাজার লুক করার পরিকল্পনা করার সময় নোডের সাথে তথ্য সংযুক্ত করুন (যেমন চাইল্ড.ড্যাটাসেটের মাধ্যমে)। লক্ষ্য হ'ল একটি ও (এন) বা ও (এন ^ 2) অ্যালগরিদমকে ও (1) অ্যালগরিদমে রূপান্তর করা। নেতিবাচক দিকটি হ'ল যদি নোডগুলি নিয়মিত যোগ করা হয় এবং সরানো হয় তবে নোডগুলির সাথে যুক্ত সম্পর্কিত অবস্থান সম্পর্কিত তথ্যও আপডেট করতে হবে, যার ফলে কোনও কার্যকারিতা লাভ হবে না। মাঝে মাঝে পুনরাবৃত্তি কোনও বড় বিষয় নয় (যেমন ক্লিক হ্যান্ডলার ক্লিক করুন) তবে পুনরাবৃত্তি পুনরাবৃত্তি সমস্যাযুক্ত (যেমন মাউসমোভ)।
কিউবিকসফট

উত্তর:


122

আপনি previousSiblingফিরে না আসা nullএবং আপনি কত ভাইবোনের মুখোমুখি হয়েছেন তা গণনা না করা পর্যন্ত আপনি ভাইবোনদের মধ্য দিয়ে ফিরে যেতে সম্পত্তিটি ব্যবহার করতে পারেন :

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

দয়া করে নোট করুন যে জাভার মতো ভাষায়, একটি getPreviousSibling()ফাংশন রয়েছে, তবে জেএসে এটি একটি সম্পত্তি হয়ে দাঁড়িয়েছে - previousSibling


2
হাঁ। আপনি যদিও লেখায় একটি getPreLiveSibling () রেখে গেছেন।
টিম ডাউন

7
শিশুদের সূচক নির্ধারণের জন্য এই পদ্ধতির জন্য একই সংখ্যক পুনরাবৃত্তি প্রয়োজন, সুতরাং এটি কীভাবে আরও দ্রুত হবে তা আমি দেখতে পাচ্ছি না।
মাইকেল 21

31
একটি লাইন সংস্করণ:for (var i=0; (node=node.previousSibling); i++);
স্কট মাইলস

2
@ এসফারবোটা জাভাস্ক্রিপ্ট ব্লক স্কোপিং জানেন না, তাই অ্যাক্সেসযোগ্য iহবে।
আরপুন

3
@ নেদেবদেব এটি কারণ হতে পারে .previousSiblingএবং এর মধ্যে পার্থক্যের কারণে .previousElementSibling। প্রাক্তন পাঠ্য নোডগুলি হিট করে, পরবর্তীটি তা করে না।
abluejelly

132

আমি এটির জন্য ব্যবহারের অনুরাগী হয়েছি 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 সূচক = [] .indexOf.call (চাইল্ড.প্যারেন্টনোড.চাইল্ডেন, চাইল্ড);
সিক্সিপিং

23
Fww, ব্যবহার []আপনি যখনই কোডটি চালান ততবারে একটি অ্যারে উদাহরণ তৈরি করে যা মেমরির জন্য কম দক্ষ এবং জিসি বনাম ব্যবহারের ক্ষেত্রে কার্যকর Array.prototype
স্কট মাইলস

@ স্কটমাইলস আপনি কি আরও কিছু বলেছিলেন তা ব্যাখ্যা করতে বলব? []ময়লা আবর্জনার মান হিসাবে পরিষ্কার হয় না ?
mrRiiha

14
[].indexOfইঞ্জিনটি মূল্যায়নের indexOfজন্য প্রোটোটাইপের প্রয়োগটি অ্যাক্সেস করার জন্য একটি অ্যারে উদাহরণ তৈরি করতে হবে । উদাহরণটি নিজেই অব্যবহৃত হয়ে পড়ে (এটি জিসি করে, এটি কোনও ফুটো নয়, এটি কেবল চক্র নষ্ট করে)। Array.prototype.indexOfঅজানা উদাহরণ বরাদ্দ না করে সরাসরি প্রয়োগ করে এমন অ্যাক্সেস করে। পার্থক্য প্রায় সব পরিস্থিতিতেই নগণ্য হতে চলেছে, তাই প্রকৃতপক্ষে এটি যত্ন নেওয়া ভাল নাও হতে পারে।
স্কট মাইলস

3
আইই তে ত্রুটি থেকে সাবধান! ইন্টারনেট এক্সপ্লোরার 6, 7 এবং 8 এটি সমর্থন করে তবে ভুলভাবে মন্তব্য নোড অন্তর্ভুক্ত করে। উত্স " বিকাশকারী.মোজিলা.আর.ইন-
ইউএস

101

ES6:

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

ব্যাখ্যা:

  • element.parentNode.childrenThat সেই elementউপাদান সহ ভাইদের ফিরিয়ে দেয় ।

  • Array.fromAn childrenকোনও Arrayঅবজেক্টের কনস্ট্রাক্টরকে কাস্ট করে

  • indexOfApply আপনি আবেদন করতে পারেন indexOfকারণ আপনার কাছে এখন একটি Arrayবিষয় রয়েছে।


2
সর্বাধিক মার্জিত সমাধান,
অমিত সাক্সেনা

1
তবে কেবল ক্রোম 45 এবং ফায়ারফক্স 32 থেকে উপলব্ধ এবং ইন্টারনেট এক্সপ্লোরারে মোটেই উপলব্ধ নয়।
পিটার

ইন্টারনেট এক্সপ্লোরার এখনও বেঁচে আছে? জাস্ট জক .. ঠিক আছে তাই আপনার ইন্টারনেট এক্সপ্লোরার নিয়ে কাজ করার জন্য একটি পলিফিলের প্রয়োজনArray.from
আবদেনর টুমি

9
এমডিএন অনুসারে, অ্যারে.ফ্রোমকে কল করা ()creates a new Array instance from an array-like or iterable object. কেবল একটি সূচী সন্ধানের জন্য একটি নতুন অ্যারের উদাহরণ তৈরি করা স্মৃতি বা জিসি দক্ষ নাও হতে পারে, নির্ভর করে অপারেশনটি কত ঘন ঘন, যা ক্ষেত্রে স্বীকৃত উত্তরে বর্ণিত হিসাবে পুনরাবৃত্তিটি আরও বেশি হবে আদর্শ।
TheDarkIn1978

1
@ TheDarkIn1978 আমি জানি সচেতনভাবে কোড লাবণ্য এবং অ্যাপ্লিকেশন পারফরম্যান্সের মধ্যে লেনদেন বন্ধ রয়েছে 👍🏻
অ্যাডেননর টুমি

38

এস-অপেক্ষাকৃত ছোট

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

স্প্রেড অপারেটর এটির জন্য একটি শর্টকাট


এটি একটি আকর্ষণীয় অপারেটর।
সমস্ত শ্রমিক

মধ্যে পার্থক্য কি e.parentElement.childNodesএবং e.parentNode.children?
মেসকিব

4
childNodesপাঠ্য নোডগুলিও অন্তর্ভুক্ত করে
ফিলিপ

টাইপস্ক্রিপ্টের সাথে আপনি পাবেন Type 'NodeListOf<ChildNode>' must have a '[Symbol.iterator]()' method that returns an iterator.ts(2488)
জেনভেন্টজি

9

একটি (সুরক্ষার জন্য পূর্বনির্ধারিত) উপাদান যুক্ত করা হচ্ছে getgetParentIndex ():

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>

সীমাবদ্ধতা

  • সমাধানটির এই বাস্তবায়ন আইই 8 এবং নীচে কাজ করবে না।

বাইনারি ভিএস লিনিয়ার অনুসন্ধান 200 হাজার উপাদানগুলিতে (কিছু মোবাইল ব্রাউজার ক্র্যাশ হতে পারে, সাবধান!):

  • এই পরীক্ষায় আমরা দেখতে পাচ্ছি যে মধ্যবর্তী উপাদান ভিএসকে বাইনারি অনুসন্ধান করতে লিনিয়ার অনুসন্ধানের জন্য কতক্ষণ সময় লাগে। কেন মাঝারি উপাদান? কারণ এটি অন্যান্য সমস্ত অবস্থানের গড় অবস্থানে রয়েছে, সুতরাং এটি সম্ভাব্য সমস্ত অবস্থানের সেরা উপস্থাপন করে।

বাইনারি অনুসন্ধান

পিছনের দিকে (`lastIndexOf`) লিনিয়ার অনুসন্ধান

সামনের দিকে (`indexOf`) লিনিয়ার সন্ধান

পূর্ববর্তী উপাদানসিবলিং কাউন্টার অনুসন্ধান

প্যারেন্ট ইনডেক্স পেতে পূর্ববর্তী উপাদান সংখ্যার সংখ্যা গণনা করে।

কোন অনুসন্ধান

ব্রাউজারটি অনুসন্ধানটি অপ্টিমাইজ করে দিলে পরীক্ষার ফলাফল কী হবে তা বেঞ্চমার্কিংয়ের জন্য।

কনকুলশন

তবে, ক্রোমে ফলাফলগুলি দেখার পরে, ফলাফলগুলি প্রত্যাশিত বিপরীত। ডাম্বার ফরোয়ার্ড লিনিয়ার অনুসন্ধান বাইনারি অনুসন্ধানের চেয়ে দ্রুত 187 এমএস, 3850% ছিল। স্পষ্টতই, ক্রোম কোনওভাবে যাদুকরীভাবে আউটসামার্ট করেছিল console.assertএবং এটিকে অপ্টিমাইজ করেছে, বা (আরও আশাবাদী) ক্রোম অভ্যন্তরীণভাবে ডিওমের জন্য সংখ্যাসূচক ইনডেক্সিং সিস্টেম ব্যবহার করে এবং কোনও অভ্যন্তরীণ ক্ষেত্রে Array.prototype.indexOfব্যবহার করার সময় প্রয়োগ করা অপ্টিমাইজেশনের মাধ্যমে এই অভ্যন্তরীণ সূচক সিস্টেমটি উদ্ভাসিত হয় HTMLCollection


দক্ষ, তবে অযৌক্তিক।
আপেলমোনকি 496

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

কাজ করে না। আমি উল্লেখ করতে বাধ্য হলাম যে আইই সংস্করণ এবং "অন্যান্য ব্রাউজার" সংস্করণ বিভিন্ন ফলাফল গণনা করবে। "অন্যান্য ব্রাউজারগুলি" কৌশলটি প্রত্যাশার মতো কাজ করে, প্যারেন্ট নোডের নীচে নবম অবস্থান অর্জন করে, তবে আইই প্রযুক্তিটি "ডকুমেন্টের সমস্ত সংগ্রহের মধ্যে অবজেক্টটি প্রদর্শিত হওয়ার সাথে সাথে উত্স অনুসারে বস্তুর অর্ডিনাল অবস্থানটি পুনরুদ্ধার করে" ( এমএসডিএন.মাইক্রোসফট) .com / en-gb / লাইব্রেরি / ie / ms534635 (v = vs.85) .aspx )। যেমন আমি "আইই" কৌশলটি ব্যবহার করে 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? ফাংশনগুলি দরকারী দেখায় তবে এই ফাংশনগুলি কী করে তা আমি জানি না (এমনকি নামগুলি সুস্পষ্ট হলেও)।
আরপুন

@ এলিমেন্ট.প্রোটোটাইপ বাড়ানোর কারণটি মিল রয়েছে ... 4 প্রাক্তন ইলেমেন.চিল্ডেন, এলিমেন্ট.প্যারেন্টনোড ইত্যাদি ... সুতরাং আপনি এলিমেন্ট.সাইবারিংগুলিকে সম্বোধন করেন .... গ্রুপ পদ্ধতিটি একটি জটিল জটিল কারণ আমি প্রসারিত করতে চাই একই নোডটাইপ অনুসারে এলিমেটসে অল্প সংখ্যক ভাইবোন পন্থা এবং একই বৈশিষ্ট্য এমনকি পূর্বপুরুষেরও নেই
বোর্টুনাক

প্রোটোটাইপ কী প্রসারিত তা আমি জানি তবে আপনার কোডটি কীভাবে ব্যবহৃত হয় তা আমি জানতে চাই। el.group.value()??। আপনার উত্তরটির গুণমান উন্নত করতে আমার প্রথম মন্তব্য।
আরপুন

গোষ্ঠী এবং ভাইবোনের পদ্ধতিগুলি প্রতিষ্ঠিত ডোম উপাদানগুলির সাথে অ্যারে ফিরিয়ে দেয় .. .... আপনার মন্তব্যের জন্য এবং মন্তব্যের কারণ হিসাবে ধন্যবাদ
বার্টুনাক

খুব মার্জিত, তবুও খুব ধীর।
জ্যাক গিফিন


-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 দরকার নেই।
ভাইটালি জাদানেভিচ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.