รับดัชนีองค์ประกอบเป็นลูกที่สัมพันธ์กับพาเรนต์


160

สมมติว่าฉันมีมาร์กอัปนี้:

<ul id="wizard">
    <li>Step 1</li>
    <li>Step 2</li>
</ul>

และฉันมี jQuery นี้:

$("#wizard li").click(function () {
    // alert index of li relative to ul parent
});

ฉันจะรับดัชนีของเด็กที่liเกี่ยวข้องกับผู้ปกครองของมันได้อย่างไรเมื่อคลิกที่li?

ตัวอย่างเช่นเมื่อคุณคลิก "ขั้นตอนที่ 1" เครื่องหมายalert"0" จะปรากฏขึ้น

คำตอบ:


247
$("#wizard li").click(function () {
    console.log( $(this).index() );
});

อย่างไรก็ตามแทนที่จะแนบ handler คลิกเดียวสำหรับแต่ละรายการมันจะดีกว่า (ประสิทธิภาพฉลาด) การใช้delegateซึ่งจะมีลักษณะเช่นนี้:

$("#wizard").delegate('li', 'click', function () {
    console.log( $(this).index() );
});

ใน jQuery 1.7+ onคุณควรใช้ ตัวอย่างด้านล่างเชื่อมเหตุการณ์กับ#wizardองค์ประกอบทำงานเหมือนเหตุการณ์ตัวแทน:

$("#wizard").on("click", "li", function() {
    console.log( $(this).index() );
});

3
สวัสดี redsquare .. ฉันกำลังฝึกหัดกับ jQuery ฉันชอบ n00b เกี่ยวกับผู้แทน: D .. ทำไมผู้แทนดีกว่าการแนบกิจกรรมโดยตรงกับองค์ประกอบต่างๆ
stecb

1
@steweb - เฮ้ - เพราะตัวจัดการเหตุการณ์หนึ่งเป็นที่นิยมมากกว่าหลายคน การแนบกิจกรรมกับ dom อาจมีค่าใช้จ่ายสูงหากคุณมีรายการขนาดใหญ่ดังนั้นตามกฎฉันพยายามใช้ด้านบนที่เป็นไปได้แทนที่จะจัดการแต่ละรายการในแต่ละองค์ประกอบ บทความหนึ่งที่เจาะลึกลงไปคือbriancrescimanno.com/2008/05/19/ … - นอกจากนี้ยังมี Google 'การมอบหมายกิจกรรมจาวาสคริปต์'
redsquare

ตกลงดังนั้นการจัดการกิจกรรมด้วยวิธีนี้มันเป็นสิ่งที่เบากว่า 'เอกสารแนบ dom' คลาสสิก :) .. ขอบคุณ!
stecb

@steweb - มันยังเบากว่าเพราะ jQuery ไม่จำเป็นต้องทำการค้นหาเบื้องต้นขององค์ประกอบ li ทั้งหมด เพียงแค่ค้นหาคอนเทนเนอร์และฟังในระดับนั้นเพื่อดูว่าวัตถุที่ถูกคลิกนั้นเป็น li หรือไม่
redsquare

วิธีการ .exex นี้เป็นประโยชน์อย่างยิ่งสำหรับฉัน ฉันใช้ jQuery Sortable เพื่อทำการเรียงลำดับ แต่เก็บข้อมูลการจัดอันดับความหมายใน DOM ด้วย. index () ฉันสามารถดึงอันดับออกมาจากโดมได้อย่างหมดจด ขอบคุณ!
SimplGy

41

สิ่งที่ต้องการ:

$("ul#wizard li").click(function () {
  var index = $("ul#wizard li").index(this);
  alert("index is: " + index)
});

9
การเพิ่มที่ยอดเยี่ยม - เราสามารถค้นหาดัชนีที่ค่อนข้างตรงกับตัวเลือกหลัก +1
BasTaller

1
ชอบคำตอบนี้จริง ๆ แล้วมันตอบคำถามค่อนข้างเป็นทางออกที่เป็นไปได้สำหรับตัวอย่าง
DarkMukke


4

ไม่จำเป็นต้องใช้ไลบรารีขนาดใหญ่เช่น jQuery เพื่อทำสิ่งนี้ให้สำเร็จหากคุณไม่ต้องการ เพื่อให้บรรลุสิ่งนี้ด้วยการจัดการ DOM ในตัวรับชุดliพี่น้องในอาร์เรย์และเมื่อคลิกตรวจสอบindexOfองค์ประกอบคลิกในอาร์เรย์นั้น

const lis = [...document.querySelectorAll('#wizard > li')];
lis.forEach((li) => {
  li.addEventListener('click', () => {
    const index = lis.indexOf(li);
    console.log(index);
  });
});
<ul id="wizard">
    <li>Step 1</li>
    <li>Step 2</li>
</ul>

หรือด้วยการมอบหมายกิจกรรม:

const lis = [...document.querySelectorAll('#wizard li')];
document.querySelector('#wizard').addEventListener('click', ({ target }) => {
  // Make sure the clicked element is a <li> which is a child of wizard:
  if (!target.matches('#wizard > li')) return;
  
  const index = lis.indexOf(target);
  console.log(index);
});
<ul id="wizard">
    <li>Step 1</li>
    <li>Step 2</li>
</ul>

หรือหากองค์ประกอบย่อยอาจเปลี่ยนแปลงแบบไดนามิก (เช่นเดียวกับรายการสิ่งที่ต้องทำ) คุณจะต้องสร้างอาร์เรย์ของlis ในการคลิกทุกครั้งแทนที่จะเป็นล่วงหน้า:

const wizard = document.querySelector('#wizard');
wizard.addEventListener('click', ({ target }) => {
  // Make sure the clicked element is a <li>
  if (!target.matches('li')) return;
  
  const lis = [...wizard.children];
  const index = lis.indexOf(target);
  console.log(index);
});
<ul id="wizard">
    <li>Step 1</li>
    <li>Step 2</li>
</ul>


$ (... ). indexOf ไม่ใช่ฟังก์ชั่น
Kareem

2
ตัวอย่างโค้ดในคำตอบของฉันไม่มีข้อผิดพลาดดังกล่าว - คุณสามารถกด "เรียกใช้ข้อมูลโค้ด" เพื่อดูว่าทำงานได้หรือไม่ หากคุณได้รับข้อผิดพลาดคุณกำลังใช้รหัสอื่น - ดูเหมือนว่าคุณกำลังใช้ jQuery แต่คำตอบของฉันแสดงวิธีการทำสิ่งนี้ให้สำเร็จโดยไม่ใช้ jQuery
CertainPerformance

ยุติธรรมพอสมควร ใช่ฉันใช้ JQuery ขอบคุณ
Kareem

3

ผู้ได้รับมอบหมายและ Live นั้นใช้งานง่าย แต่หากคุณไม่ได้เพิ่ม li: s แบบไดนามิกคุณสามารถใช้การแจกแจงเหตุการณ์ด้วยการผูก / คลิกปกติเช่นกัน ควรมีการเพิ่มประสิทธิภาพบางอย่างโดยใช้วิธีนี้เนื่องจาก DOM จะไม่ได้รับการตรวจสอบสำหรับองค์ประกอบการจับคู่ใหม่ ยังไม่ได้รับตัวเลขจริง แต่มันก็สมเหตุสมผล :)

$("#wizard").click(function (e) {
    var source = $(e.target);
    if(source.is("li")){
        // alert index of li relative to ul parent
        alert(source.index());
    }
});

คุณสามารถทดสอบได้ที่ jsFiddle: http://jsfiddle.net/jimmysv/4Sfdh/1/


1
คุณหมายถึงอะไรเมื่อคุณพูดว่า 'DOM ไม่ต้องถูกตรวจสอบ'? ผู้แทน jq ไม่ได้ตรวจสอบ dom
redsquare

@redsquare ฉันอยู่ภายใต้ความประทับใจที่ผู้ได้รับมอบหมายเป็นเพียงตัวแปรที่มีประสิทธิภาพมากขึ้นของ Live นี่คือจากapi.jquery.com/delegate : "แนบตัวจัดการกับเหตุการณ์อย่างน้อยหนึ่งรายการสำหรับองค์ประกอบทั้งหมดที่ตรงกับตัวเลือกทั้งในปัจจุบันและในอนาคตโดยยึดตามองค์ประกอบรากที่เฉพาะเจาะจง" มันจะต้องมีการตรวจสอบการผูกในอนาคตหรือไม่
jimmystormig

ไม่เพียงแค่ใช้การมอบหมายบนภาชนะเช่นรหัสของคุณด้านบน หากคุณแทรกองค์ประกอบ li ใหม่ลงในคอนเทนเนอร์เหตุการณ์การคลิกคอนเทนเนอร์จะยังคงทำงานอยู่และทุกอย่างยังใช้งานได้ ไม่จำเป็นต้องมีการตรวจสอบ
redsquare

@redsquare ใช่ถูกต้อง โซลูชันของฉันทำงานได้แม้ว่าจะมีองค์ประกอบใหม่เพิ่มหลังจากโหลด DOM แล้ว เนื่องจากผู้ได้รับมอบหมายใช้ Live ภายใน (ดูstackoverflow.com/questions/2954932/… ) มันยังคงรู้สึกว่าสิ่งนี้ได้รับการปรับให้เหมาะสมยิ่งขึ้น แต่สะดวกน้อยลง แต่อย่างที่ฉันพูดฉันไม่มีตัวเลข
jimmystormig

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.