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

发布于 2024-12-07 06:40:07 字数 1484 浏览 0 评论 0原文

我正在尝试为文档创建手风琴效果,当您单击

文档的其余部分()时带有向上和向下滑动的切换开关。然而我一直遇到问题。下面是代码:

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。但是,当我点击任何

元素时,它总是会折叠最后一个
.

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

I'm attempting to create an accordion effect for a document where when you click on an <h1> the rest of the document (the <div.container>) with toggle sliding up and sliding down. I keep running into a problem however. Here is the code:

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'

When I use the article variable in say... the console.log It rotates through the articles and prints back their ids. But when I go to click any of the <h1> elements, it always collapses the last <article>s <div.container>.

I think this is because the article variable is stored outside of the scope of the for loop in CoffeeScript and the click doesn't execute until after the loop has already completed.

If this is true, how do I guarantee that the right object is being referenced when the click event is executed? Would it be better just to use a for i in [0...3] loop and just reference the array directly? Is the problem something else entirely? Thank you for your help!

For those who may not be familiar with coffeeScript, here's the javaScript that is compiled (just ignore the _results variable):

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');
  }));
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

小糖芽 2024-12-14 06:40:07

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

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

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

The reason you are seeing this behavior is because the article referenced in the click events is not evaluated until the handler is triggered, and at that point in time, it is set to the last article which was evaluated in your loop.

This may work a bit better for you (sorry, not sure of the coffee script implementation):

$('article h1').click(function() {
    $(this).next('.container').slideToggle('slow');
});
听风吹 2024-12-14 06:40:07

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

这是一个常见的混淆领域:只有函数在 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 回调都会看到它自己的 click 迭代。 code>article,而不是在循环过程中改变值的那个。我在 PragPub 文章 A CoffeeScript Intervention 中简要讨论了这一点。

Rocco's answer is correct. Let me expand on it:

This is a common area of confusion: Only functions create scope in JavaScript (and CoffeeScript), which means that when you do something asynchronous within a loop, you have to remember to "capture" the variable. The preferred way to do that in CoffeeScript is with the do syntax, which lets you write

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

which compiles to the equivalent of

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

That way, each click callback sees its own iteration of article, not the one that changes value as you go through the loop. I talk about this briefly in my PragPub article A CoffeeScript Intervention.

同展鸳鸯锦 2024-12-14 06:40:07

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

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

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

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

Here's another way to do it (in javascript/jQuery) by:

  1. Modifying the initial selector to pick all the h1 tags under article
  2. Using this.parentNode to get the context from the click
  3. Then look for the .container object under that common parent.

This way, we don't have to store any state across the click as we can just find the container that shares the same parent with the item that is clicked on. This method also doesn't rely on the exact position of the container object relative to the h1 that is clicked on - it just needs the container to share the same parent so it's more flexible in future layout.

$('article h1').click(function() {
    $('.container', this.parentNode).slideToggle('slow');
});
牵你手 2024-12-14 06:40:07

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

这一行:

article = articles[_i];

应该这样读:

var article = articles[_i];

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

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

I don't know anything about Coffeescript, but the compiled Javascript has a pretty obvious bug.

This line:

article = articles[_i];

Should read like this:

var article = articles[_i];

With this change, the article variable will be considered part of the calling scope and reference the appropriate element when it comes time to call your handler (rather than referencing an implicit global variable). That's all you need to fix your bug.

Hopefully there's a way to specify that in Coffeescript, but it seems pretty horrendous that for article in articles doesn't do that automatically.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文