【问题标题】:JQuery function still running after attribute change属性更改后 JQuery 函数仍在运行
【发布时间】:2014-06-15 01:13:57
【问题描述】:

我的页面上有一个菜单。单击每个菜单项时,它会调用以下功能之一:

$('.sideNav1').click(function(){
    $('.sideNav1').attr('class','selected1');
    $('.selected2').attr('class','sideNav2');
    $('.selected3').attr('class','sideNav3');
    alert("1 selected");
    return false;
});

$('.sideNav2').click(function(){
    $('.sideNav2').attr('class','selected2');
    $('.selected1').attr('class','sideNav1');
    $('.selected3').attr('class','sideNav3');
    alert("2 selected");
    return false;
});

$('.sideNav3').click(function(){
    $('.sideNav3').attr('class','selected3');
    $('.selected2').attr('class','sideNav2');
    $('.selected1').attr('class','sideNav1');
    alert("3 selected");
    return false;
});

HTML:

<div class="sideNav1">
Nav 1
</div>
<div class="sideNav2">
Nav 2
</div>
<div class="sideNav3">
Nav 3
</div>

在属性更改之后(根据 chrome 中的开发工具,确实发生了),我希望选定的 div 在单击时不会执行任何操作。相反,它的行为就像没有属性更改一样,并且仍然调用 click() 事件侦听器以使 .sideNav... 再次运行该函数。

这里有什么我可能遗漏的吗?

【问题讨论】:

    标签: javascript jquery


    【解决方案1】:

    jQuery 静态事件处理程序(您正在使用的类型),在您第一次运行代码时绑定事件处理程序一次。之后对类名的任何更改都是无关紧要的,并且不会以任何方式影响事件处理程序。

    对于传播的事件,您可以使用委托事件处理来评估每个事件的选择器匹配。在委托事件处理中,您将事件绑定到一个静态父对象(其 DOM 元素在您安装事件处理程序时存在,并且在任何时候都不会重新创建)并且您使用.on() 的委托形式。

    在您的情况下,您必须选择静态父级的选择器并使用如下内容:

    $(some parent selector).on("click", ".sideNav1", function() {...});
    

    虽然最好(出于大页面的性能原因)使用比&lt;body&gt; 元素更近的父元素,但您甚至可以这样做:

    $(document.body).on("click", ".sideNav1", function() {...});
    

    然后,只有当目标对象具有.sideNav1 类名时才会调用事件处理程序,而没有时则不会。

    委托事件处理的工作方式如下:

    1. 像“点击”事件这样的一些事件会沿父链向上传播。在目标对象上调用它们之后,它们会在链上的任何父对象上调用,一直到 document 对象,或者直到有人在其上调用 .stopPropagation()

    2. 因此,如果您为父对象上的特定事件安装事件处理程序,您可以看到发生在子对象上的所有事件(假设没有人对它们调用 .stopPropagation())。

    3. 使用.on() 的委托形式,jQuery 将检查在父级上调用的每个事件,以查看事件的原始目标是否与传递的第二个选择器匹配,并在运行时在事件发生时检查它.由于此检查在事件分发时是实时的,因此它会受到您对 DOM 元素所做的任何动态更改的影响(如您的情况)。

    您可以在这些参考资料中阅读有关使用委托事件处理的更多信息:

    jQuery .live() vs .on() method for adding a click event after loading dynamic html

    jQuery selector doesn't update after dynamically adding new elements

    jQuery .on does not work but .live does

    Does jQuery.on() work for elements that are added after the event handler is created?

    JQuery Event Handlers - What's the "Best" method

    这些答案中更常见的情况是在您安装事件处理程序后添加或重新创建的 DOM 元素,但问题与您修改它们上的类并期望事件的 DOM 元素几乎相同处理程序来改变他们的行为。


    仅供参考,我通常还建议您使用 .addClass().removeClass() 而不是 .attr(),因为这允许您程序的其他部分在这些对象上使用其他类(出于样式或其他原因)。

    【讨论】:

    • 感谢您的快速回复!要使用您的方法,我是否必须将 HTML 更改为 &lt;div class="parentSideNav"&gt;&lt;div class="sideNav1"&gt;Nav 1&lt;/div&gt;&lt;/div&gt;
    • @matt1985 - 你可以使用任何共同的父母。它不必是直接父母。你不知道你的 HTML,但是如果你有任何通用的容器 div,你可以使用它——你不一定要添加一个新的容器对象。您甚至可以使用body 对象作为公共父对象,尽管您可以选择的父对象越近,性能就会越好(只有当您将大量委托事件处理程序附加到同一对象时,性能才会有所不同同一页)。
    • 感谢您不仅提供了解决方案,还提供了非常深入的解释。我知道 147k 代表来自哪里 :)
    【解决方案2】:

    如果你为所有的 div 添加一个 sideNav 类,你可以这样做:

    $('.sideNav').click(function(){
        $('.sideNav').removeClass("selected");
        $(this).addClass("selected");
    
    });
    

    Jsfiddle 示例:http://jsfiddle.net/Tec3D/

    【讨论】:

      【解决方案3】:

      好的,我从live改为on...

         $(document).on('click','.sideNav1',function(){
          $(this).unbind('click').attr('class','selected1');
          $('.selected2').attr('class','sideNav2').bind('click');
          $('.selected3').attr('class','sideNav3').bind('click');
          alert("1 selected");
          return false;
      });
      
      $(document).on('click','.sideNav2',function(){
           $(this).unbind('click').attr('class','selected2');
          $('.selected1').attr('class','sideNav1').bind('click');
          $('.selected3').attr('class','sideNav3').bind('click');
          alert("2 selected");
          return false;
      });
      
      $(document).on('click','.sideNav3',function(){     
          $(this).unbind('click').attr('class','selected3');
          $('.selected2').attr('class','sideNav2').bind('click');
          $('.selected1').attr('class','sideNav1').bind('click');
          alert("3 selected");
          return false;
      });
      

      http://jsfiddle.net/BHL84/14/

      【讨论】:

      • .live() 已被弃用很长时间,现在已从最新版本的 jQuery 中删除。不推荐。 .on() 的委托形式是它的替换。有关替换 .live() 的讨论,请参阅我的答案中的参考资料。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多