jQuery.each () проблема - PullRequest
       45

jQuery.each () проблема

2 голосов
/ 16 июля 2009

Я постараюсь сохранить это коротким. Я пытаюсь создать текстовые поля, которые скрываются или отображаются, когда пользователь нажимает кнопку раскрытия. Я использую метод toggle ().

Разметка такая:

<span id="toggle0">+</span>
<div id="toggle0Container">
    blablabla...
<div>

<span id="toggle1">+</span>
<div id="toggle1Container">
    blablabla...
<div>

<span id="toggle2">+</span>
<div id="toggle2Container">
    blablabla...
<div>

// etc

Предполагается, что # toggle0 переключает # toggle0Container, # toggle1 переключает # toggle1Container и так далее. Все это генерируется PHP, поэтому может быть любое количество этих контейнеров.

Вот код JQuery:

$(document).ready(function() {
    // array of numbers, it's pretty redundant, there will never be more than 30 containers
    var arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9 , 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36];
    // hide all containers first
    jQuery.each(arr, function() {
        $('#toggle' + this + 'Container').hide();
    });
    // now the toggle buttons
    jQuery.each(arr, function() {
        $('#toggle' + this).click(function() {
            // this line is not working
            $('#toggle' + this + 'Container').slideToggle('slow');
            // and this just changes the toggle button from + to -
            if ($(this).html() == '+') {
                $(this).html('-');
            } else {
                $(this).html('+');
            }
        });
    });
});

Это работает за исключением переключающей части (я добавил комментарий над строкой, которая не работает). Где проблема?

Ответы [ 8 ]

5 голосов
/ 16 июля 2009

Это потому, что «this» теперь находится в другой области видимости и относится к фактическому элементу DOM #toggleN, а не к одному из чисел в массиве.

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


$("div[id^=toggle][id$=container]").hide();

$("span[id^=toggle]").click(function() {
     $(this).find("span[id^=toggle][id$=container]").slideToggle("slow");
     // .. do your other html stuff
}

Просто отбросьте их и замените переключатели на них.

2 голосов
/ 16 июля 2009

Я бы следовал подходу mgroves, но если вы действительно хотите сделать массив, или просто хотите выяснить, как правильно использовать each (), вот как вы должны его использовать:

$(document).ready(function() {
    // array of numbers, it's pretty redundant, there will never be more than 30 containers
    var arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9 , 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36];
    // hide all containers first
    jQuery.each(arr, function(index, item) {
        $('#toggle' + item + 'Container').hide();
    });
    // now the toggle buttons
    jQuery.each(arr, function(index, item) {
        $('#toggle' + item).click(function() {
            // this line is not working
            $('#toggle' + item + 'Container').slideToggle('slow');
            // and this just changes the toggle button from + to -
            if ($(this).html() == '+') {
                $(this).html('-');
            } else {
                $(this).html('+');
            }
        });
    });
});
2 голосов
/ 16 июля 2009

EDIT

Мне больше нравится решение mgroves для вашего конкретного случая использования, но я оставлю свой ответ, объясняющий, как вы можете принять индекс и элемент в качестве параметра для метода .each

ОРИГИНАЛЬНЫЙ ОТВЕТ

Как уже говорили другие, контекст this - это не то, что вы думаете, это тот момент, когда вы на него ссылаетесь. Вот отличная статья Реми Шарпа под названием « jQuery's this: demystified », которую я рекомендую вам прочитать.

функция .each может принимать два параметра, которые вам очень помогут, и вам не понадобится этот массив чисел.

$('span[id^=toggle']').each(function(idx, elem) {

    // idx is the current index of the jQuery object
    $('#toggle' + idx).click(function() {

        // elem is the current element
        $(elem).next('#toggle' + idx + 'Container').slideToggle('slow');

        if ($(elem).html() == '+') {
            $(elem).html('-');
        } else {
            $(elem).html('+');
        }

    });

});
1 голос
/ 16 июля 2009

Я собирался опубликовать именно то, что Макс сделал с использованием класса. Я бы только улучшил его предложение с помощью этого более простого селектора, чтобы найти контейнер:

$(function() {
  // hide all containers first
  $(".container").hide();
  // now the toggle buttons
  $(".toggler").click(function() {
    $(this).next().slideToggle("slow");

    if (container.is(":visible")) {
      $(this).html("-");
    }
    else {
      $(this).html("+");
    }
  });
});

Если вы не можете легко получить классы на участках, вы, вероятно, можете создать подобный селектор, используя что-то вроде $ ('# SpanContainer> span'), чтобы выбрать их по имени тега, по убыванию с содержащего его элемента.

1 голос
/ 16 июля 2009

Как сказал mgroves, ваша сфера становится все изнуренной с помощью каждого (). См. это для получения дополнительной информации.

1 голос
/ 16 июля 2009

Я бы предложил добавить класс к вашей кнопке переключения (span), например «toggler», и к вашему контейнеру переключателя, например «container», или что-то еще, чтобы упростить ваш JavaScript:

$(function() {
    // hide all containers first
    $(".container").hide();
    // now the toggle buttons
    $(".toggler").click(function() {
          var container = $("#" + $(this).attr("id") + "Container");
          container.slideToggle("slow");

          $(this).html(container.is(":visible") ? "-" : "+");
    });
});

Дайте этому шанс.

0 голосов
/ 16 июля 2009

Вы должны дать своим элементам класс, по которому можно искать, а затем использовать next.

Сделайте вашу разметку примерно такой:

<span class="toggleButton">+</span>
<div class="toggleContainer">
   blablabla...
<div>

Теперь ваш код для обработки этого становится таким простым:

$('.toggleButton').click(function() {
    $(this).next('.toggleContainer').slideToggle('slow');
});
0 голосов
/ 16 июля 2009

Я недавно написал довольно содержательный скрипт для поведения, подобного этому. Я выбрал немного другой путь, потому что решил обернуть все элементы данного элемента hide / show в содержащий div. Он позволяет вам иметь несколько «триггеров» для одного раздела, если вам это нужно, и вы можете добавить произвольное количество элементов скрытия / показа, не беспокоясь о их нумерации. Я бы структурировал это примерно так:

<div class="expSecWrapper">
    <div class="expSecTrigger">Insert Trigger Here</div>
    <div class="expSecBody">
        Content to hide/show
    </div>
</div>

И тогда код jQuery будет выглядеть примерно так:

$(document).ready(function(){
    var targets = $(".expSecWrapper")
    targets.find(".expSecTrigger").click(function(){
        targets.find(".expSecBody").hide()
        $(this).parents(".expSecWrapper").eq(0).children(".expSecBody").toggle();
    })
})

Вы можете добавить в оставшиеся соответствующие JS для вашего приложения.

У него есть несколько ограничений, таких как необходимость того, чтобы тело скрытия / показа было прямым потомком обертки. Это может быть применено к выпадающим спискам, переключателям, что угодно. Это также гнездо, так что вы можете иметь несколько уровней, если скрыть / показать.

И последнее: вам даже не нужно использовать итератор .each для назначения этого поведения. Нечто подобное .click () назначит поведение всей группе объектов jQuery. Пока вы используете селектор, который захватит все ваши цели.

Извините, пару раз пришлось редактировать.

...