激活click事件时引用的对象错误

时间:2011-09-27 19:35:50

标签: javascript jquery coffeescript

我正在尝试为文档创建一个手风琴效果,当您单击<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。但是当我点击任意<h1>个元素时,它总是会折叠最后<article><div.container>

我认为这是因为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');
  }));
}

4 个答案:

答案 0 :(得分:3)

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

这可能会对你有所帮助(对不起,不确定咖啡脚本的实现):

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

答案 1 :(得分: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中简要地讨论了这个问题。

答案 2 :(得分:1)

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

  1. 修改初始选择器以选择文章
  2. 下的所有h1标签
  3. 使用this.parentNode从点击
  4. 获取上下文
  5. 然后在该公共父级下查找.container对象。
  6. 这样,我们不必在点击中存储任何状态,因为我们可以找到与点击的项目共享同一父节点的容器。此方法也不依赖于容器对象相对于单击的h1的确切位置 - 它只需要容器共享同一个父级,以便在将来的布局中更灵活。

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

答案 3 :(得分:0)

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

这一行:

article = articles[_i];

应该是这样的:

var article = articles[_i];

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

希望有一种方法可以在Coffeescript中指定,但是文章中的文章不会自动执行此操作似乎非常可怕。