Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/441.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 激活单击事件时引用了错误的对象_Javascript_Jquery_Coffeescript - Fatal编程技术网

Javascript 激活单击事件时引用了错误的对象

Javascript 激活单击事件时引用了错误的对象,javascript,jquery,coffeescript,Javascript,Jquery,Coffeescript,我正在尝试为文档创建一种手风琴效果,当您单击时,文档的其余部分(即)将使用上下滑动切换。然而,我一直遇到一个问题。代码如下: HTML 当我在say中使用article变量时。。。console.log它在文章中循环并打印回它们的ID。但是当我点击任何元素时,它总是折叠最后一个s 我认为这是因为article变量存储在CoffeeScript中for循环的范围之外,并且直到循环完成后才执行单击 如果这是真的,我如何保证在执行click事件时引用了正确的对象?在[0…3]循环中,对i使用并直接引用

我正在尝试为文档创建一种手风琴效果,当您单击
时,文档的其余部分(即
)将使用上下滑动切换。然而,我一直遇到一个问题。代码如下:

HTML

当我在say中使用
article
变量时。。。
console.log
它在文章中循环并打印回它们的ID。但是当我点击任何
元素时,它总是折叠最后一个
s

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

如果这是真的,我如何保证在执行click事件时引用了正确的对象?在[0…3]循环中,对i使用
并直接引用数组是否更好?这个问题完全是另外一回事吗?谢谢你的帮助

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

var文章
articles=$('article').toArray();
_结果=[];
对于(_i=0,_len=articles.length;_i<_len;_i++){
第条=第[_i]条;
_结果。推送($('h1',文章)。单击(函数(){
返回$('.container',article.slideToggle('slow');
}));
}

您看到此行为的原因是,在触发处理程序之前,
单击
事件中引用的
文章
不会计算,并且在该时间点,它被设置为在循环中计算的最后一篇文章

这可能会对您更好一些(抱歉,不确定coffee脚本的实现):


下面是另一种方法(在javascript/jQuery中),方法是:

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

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

    我对Coffeescript一无所知,但编译后的Javascript有一个非常明显的bug

    这一行:

    article = articles[_i];
    
    应该这样读:

    var article = articles[_i];
    
    通过此更改,article变量将被视为调用范围的一部分,并在调用处理程序时引用相应的元素(而不是引用隐式全局变量)。这就是修复bug所需的全部内容


    希望有一种方法可以在Coffeescript中指定这一点,但似乎很可怕的是,文章中的for-article并没有自动做到这一点。

    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)
    

    这样,每个
    单击
    回调都会看到自己的
    文章的迭代,而不是在循环过程中更改值的迭代。我在PragPub的文章中简要地谈到了这一点。

    事实上,CoffeeScript确实创建了一个
    var文章
    声明;迈克尔只是省略了它。不过,这并不能解决这里的问题,因为正如Rocco在
    点击
    回调中指出的那样,
    文章从循环结束时就有了它的价值。我将标记Rocco作为答案,因为他第一次出现,但看到JavaScript中有多少解决方案总是很好的。谢谢你们的帮助!
    
    article = articles[_i];
    
    var article = articles[_i];
    
    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)