【问题标题】:Wrong object referenced when click event is activated激活点击事件时引用了错误的对象
【发布时间】:2011-09-28 05:43:26
【问题描述】:

我正在尝试为文档创建手风琴效果,当您单击<h1> 时,文档的其余部分(<div.container>)带有向上和向下滑动的切换开关。但是,我一直遇到问题。代码如下:

HTML

<article>
    <h1>Title</h1>
    <div class="container">
        //...
    </div>
</article>

<article>
    //...
</article>

<article>
    //...
</article>

CoffeeScript:

articles = $('article').toArray()

for article in articles
    #console.log $('.container', article).parent().attr('id')
    $('h1', article).click ->
        $('.container', article).slideToggle 'slow'

当我使用article 变量说... console.log 它在文章中旋转并打印回它们的ID。但是当我点击任何&lt;h1&gt; 元素时,它总是会折叠最后一个&lt;article&gt;s &lt;div.container&gt;

我认为这是因为 article 变量存储在 CoffeeScript 中 for 循环的范围之外,并且直到循环完成后才会执行单击。

如果是这样,我如何保证在单击事件执行时引用了正确的对象?使用for i in [0...3] 循环并直接引用数组会更好吗?问题完全是另一回事吗?感谢您的帮助!

对于可能不熟悉coffeeScript的人,这里是编译的javaScript(忽略_results变量):

var articles
articles = $('article').toArray();
_results = [];

for (_i = 0, _len = articles.length; _i < _len; _i++) {
  article = articles[_i];
  _results.push($('h1', article).click(function() {
    return $('.container', article).slideToggle('slow');
  }));
}

【问题讨论】:

    标签: javascript jquery coffeescript


    【解决方案1】:

    您看到此行为的原因是因为 click 事件中引用的 article 在触发处理程序之前不会被评估,并且在那个时间点,它被设置为最后一篇评估的文章你的循环。

    这对你来说可能会更好一些(抱歉,不确定咖啡脚本的实现):

    $('article h1').click(function() {
        $(this).next('.container').slideToggle('slow');
    });
    

    【讨论】:

    • 我将 Rocco's 标记为答案,因为他是第一个出现的,但是看到 JavaScript 中的一个问题有很多解决方案总是很高兴。谢谢大家的帮助!
    【解决方案2】:

    Rocco 的回答是正确的。让我扩展一下:

    这是一个常见的混淆区域:只有函数在 JavaScript(和 CoffeeScript)中创建范围,这意味着当您在循环中执行异步操作时,您必须记住“捕获”变量。在 CoffeeScript 中执行此操作的首选方法是使用 do 语法,它可以让您编写

    for article in articles
      do (article) ->
        $('h1', article).click ->
          $('.container', article).slideToggle 'slow'
    

    编译成等价于

    for article in articles
      ((article) ->
        $('h1', article).click ->
          $('.container', article).slideToggle 'slow'
      )(article)
    

    这样,每个click 回调都会看到自己的article 迭代,而不是在循环中改变值的那个。我在我的 PragPub 文章 A CoffeeScript Intervention 中简要谈到了这一点。

    【讨论】:

      【解决方案3】:

      这是另一种方法(在 javascript/jQuery 中):

      1. 修改初始选择器以选择文章下的所有h1标签
      2. 使用this.parentNode 从点击中获取上下文
      3. 然后在该共同父项下查找.container 对象。

      这样,我们不必在点击过程中存储任何状态,因为我们可以找到与被点击项目共享同一父项的容器。此方法也不依赖于容器对象相对于被点击的 h1 的确切位置——它只需要容器共享同一个父对象,以便在未来的布局中更加灵活。

      $('article h1').click(function() {
          $('.container', this.parentNode).slideToggle('slow');
      });
      

      【讨论】:

        【解决方案4】:

        我对Coffeescript一无所知,但是编译的Javascript有一个非常明显的错误。

        这一行:

        article = articles[_i];
        

        应该是这样的:

        var article = articles[_i];
        

        通过此更改,article 变量将被视为调用范围的一部分,并在调用您的处理程序时引用适当的元素(而不是引用隐式全局变量)。这就是您修复错误所需的全部内容。

        希望有一种方法可以在 Coffeescript 中指定它,但是 for article in article 似乎很可怕,它不会自动执行此操作。

        【讨论】:

        • 实际上,CoffeeScript 确实创建了一个var article 声明;迈克尔只是省略了它。不过,这并不能解决这里的问题,因为——正如 Rocco 指出的——从 click 回调中,article 将在循环结束时获得它的值。
        猜你喜欢
        • 1970-01-01
        • 2011-05-09
        • 2013-07-19
        • 1970-01-01
        • 1970-01-01
        • 2014-05-08
        • 1970-01-01
        • 1970-01-01
        • 2018-10-28
        相关资源
        最近更新 更多