【问题标题】:jQuery.each() troublejQuery.each() 麻烦
【发布时间】:2010-11-11 10:53:28
【问题描述】:

我会尽量保持简短。我正在尝试创建在用户单击展开按钮时隐藏或显示的文本框。我正在使用 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('+');
            }
        });
    });
});

除了切换部分(我在不起作用的行上方添加了注释)外,它都可以工作。问题出在哪里?

【问题讨论】:

    标签: jquery toggle slide


    【解决方案1】:

    这是因为“this”现在处于不同的范围内,并且指的是实际的 #toggleN DOM 元素,而不是数组中的数字之一。

    我建议您放弃数字数组,并使用不同的选择器,例如:

    
    $("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
    }
    

    只需放弃这些,并用它们替换切换选择器。

    【讨论】:

    • find 通话中的小错字,您使用的是 ^ 而不是 ^=
    【解决方案2】:

    我会遵循 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('+');
                }
            });
        });
    });
    

    【讨论】:

    • 感谢大家的回答,它们非常有用,但我会使用数组,感谢 DrJokepu 修复 each() 方法。
    • 这个答案的唯一要点是向您展示您的语法在哪里关闭。你真的,真的不应该使用它——尤其是当它在太多容器上中断时,并且牢不可破的修复要简单得多。 (不过,真正的原因是冗余数组伤害了我的eeeyyyyyeeeesssssss。)
    【解决方案3】:

    编辑

    对于您的特定用例,我更喜欢 mgroves 解决方案,但我会留下我的答案,解释如何接受索引和元素作为 .each 方法的参数

    原始答案

    正如其他人所说,this 的上下文并不是您在引用它时所认为的那样。这是 Remy Sharp 的一篇很棒的文章,标题为“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('+');
            }
    
        });
    
    });
    

    【讨论】:

      【解决方案4】:

      我建议在您的切换按钮(跨度)上放置一个类,例如“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") ? "-" : "+");
          });
      });
      

      试一试。

      【讨论】:

        【解决方案5】:

        正如 mgroves 所说,使用 each() 可以扩大您的范围。请参阅this 了解更多信息。

        【讨论】:

          【解决方案6】:

          我正要发布 Max 关于使用类的确切做法。我只会用这个更容易找到容器的选择器来改进他的建议:

          $(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') 之类的东西构造一个类似的选择器,以按标签名称选择它们,从它们的包含元素降序。

          【讨论】:

            【解决方案7】:

            你应该给你的元素一个可以被搜索的类,然后使用next

            让你的标记像这样:

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

            现在,您处理此问题的代码变得如此简单:

            $('.toggleButton').click(function() {
                $(this).next('.toggleContainer').slideToggle('slow');
            });
            

            【讨论】:

              【解决方案8】:

              我最近为这样的行为编写了一个相当丰富的脚本。我采取了稍微不同的路线,因为我选择将给定隐藏/显示元素的所有元素包装在一个包含的 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 对象组。只要您使用可以抓取所有目标的选择器。

              抱歉,不得不修改几次。

              【讨论】:

                猜你喜欢
                • 2011-06-12
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多