JQuery: this: "$ (this).next(). next()" работает, но "$ (this).next('. div')" does not

Хорошо, я пытаюсь скрыть этот набор информации.

 <img class="arrow" src="images/navigation/arrowright.png">
        <H2>More Information</H2>
    <div class="box">
        <h2>Bibendum Magna Lorem</h2>
        <p>Cras mattis consectetur purus sit amet fermentum.</p>
    </div>

 <img class="arrow" src="images/navigation/arrowright.png">
    <H2>A Second Group of Information</H2>
    <div class="box">
        <h2>Bibendum Magna Lorem</h2>
        <p>Cras mattis consectetur purus sit amet fermentum.</p>
    </div>

Он работает, когда я набираю это:

$(".arrow").click(function() {
    $(this).next().next().slideToggle();
});

но не тогда, когда я это сделаю:

$(".arrow").click(function() {
    $(this).next('.box').slideToggle();
});

Что происходит, когда второй вариант не работает? Я был у него в течение нескольких дней и не мог чертовски понять это! Я ценю ваш вклад!

Ответы

Ответ 1

Проблема

Если вы посмотрите документацию для .next(selector), он не "найдет" следующего брата, который соответствует селектору. Скорее, он смотрит на JUST следующего брата и ТОЛЬКО возвращает этот элемент, если он соответствует селектору, который не является тем, что вы хотите.

Вот что говорит doc для .next():

Описание: Получите сразу следующий родной брат каждого элемента в набор согласованных элементов. Если предусмотрен селектор, он извлекает следующего брата, только если он соответствует этому селектору.

Итак, вы можете видеть, что .next(".box") будет смотреть на элемент h2, который сразу же после вашего элемента .arrow (следующий элемент sibling), а затем сравнивает его с селектором .box и, t, он вернет пустой объект jQuery.


Решение с использованием .nextAll()

Если вам нужен следующий брат, который соответствует селектору, вы можете использовать это:

$(this).nextAll(".box").eq(0).slideToggle();

Это позволяет найти все братья и сестры, которые соответствуют селектору, а затем извлекает только первый.


Создайте свой собственный метод .findNext()

Я так часто задавался вопросом, почему у jQuery нет метода для этого, который я сам сделал:

// get the next sibling that matches the selector
// only processes the first item in the passed in jQuery object
// designed to return a jQuery object containing 0 or 1 DOM elements
jQuery.fn.findNext = function(selector) {
    return this.eq(0).nextAll(selector).eq(0);
}

И тогда вы просто используете:

$(this).findNext(".box").slideToggle();

Опция: добавьте дополнительную структуру в HTML, чтобы сделать вещи более простыми и гибкими

FYI, общий подход к таким проблемам заключается в том, чтобы помещать содержащий div div в каждый набор элементов DOM следующим образом:

<div class="container">
    <img class="arrow" src="images/navigation/arrowright.png">
    <H2>More Information</H2>
    <div class="box">
            <h2>Bibendum Magna Lorem</h2>
            <p>Cras mattis consectetur purus sit amet fermentum.</p>
    </div>
</div>

<div class="container">
     <img class="arrow" src="images/navigation/arrowright.png">
     <H2>A Second Group of Information</H2>
     <div class="box">
            <h2>Bibendum Magna Lorem</h2>
            <p>Cras mattis consectetur purus sit amet fermentum.</p>
     </div>    
</div>

Затем вы можете использовать код, который немного менее чувствителен к точному позиционированию элементов:

$(".arrow").click(function() {
    $(this).closest(".container").find(".box").slideToggle();
});

Это относится к содержащему и общему родительскому элементу с помощью .closest(), а затем использует .find() для нахождения элемента .box в этой группе.