Отримайте індекс елемента як дочірнього відносно батьківського


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

Однак замість того, щоб додавати один обробник клацання для кожного елемента списку, краще (з розумом виконання) використовувати такий варіант, 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 - Ей - адже один обробник подій набагато кращий для потенційно багатьох. Додавання подій до дому може бути дорогим, якщо у вас є великі списки, тому, як правило, я намагаюся використовувати вище, де це можливо, а не окремі обробники для кожного елемента. Одна стаття, яка йде глибше, - briancrescimanno.com/2008/05/19/… - також google "делегування події javascript"
червоний квадрат

ок, так, керуючи подіями таким чином, це щось легше, ніж класичне «прикріплення до дому» :) .. дякую!
stecb

@steweb - Це також легше, оскільки jquery не потребує початкового пошуку всіх елементів li. Він просто шукає контейнер і прослуховує на цьому рівні, щоб побачити, чи клацнув об'єкт, був лі.
переосмислити

Цей метод .index мені дуже допомагає. Я використовую 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>

Або, якщо дочірні елементи можуть динамічно змінюватися (як, наприклад, зі списком todo), вам доведеться побудувати масив 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

Delegate і 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 У мене було враження, що Delegate - це просто більш ефективний варіант Live. Це з api.jquery.com/delegate : "Приєднайте обробник до однієї або кількох подій для всіх елементів, які відповідають селектору, зараз або в майбутньому, на основі конкретного набору кореневих елементів." Це повинен бути моніторинг, щоб прив'язуватись у майбутньому?
jimmystormig

ні, він просто використовує делегування на контейнері, як ваш код вище. Якщо ви вставите новий елемент li в контейнер, подія натискання контейнера все ще запускається, і все працює. Моніторинг не потрібен.
переосмислити

@redsquare Так, ти прав. Моє рішення працює, навіть якщо після завантаження DOM додаються нові елементи. Оскільки Delegate використовує Live внутрішньо (див. Stackoverflow.com/questions/2954932/… ), він все ще відчуває, що це більш оптимізовано, але менш зручно. Але як я вже сказав, у мене немає номерів.
jimmystormig

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.