为什么当我在一个循环中添加一堆事件监听器时,每个元素是否触发最后添加的侦听器? [英] Why, when I add a bunch of event listeners in a loop, does every element trigger the last listener added?

查看:273
本文介绍了为什么当我在一个循环中添加一堆事件监听器时,每个元素是否触发最后添加的侦听器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在页面上,我有一个美国和加拿大的SVG地图,以及省份和州的HTML列表。悬停在任何省份,名单中的名称或其在地图上的描述,都应使名称和描述变为不同的颜色。所有的名称和路径已经有逻辑ID /类。

On a page, I have an SVG map of the US and Canada, and an HTML list of provinces and states. Hovering over any province, either its name in the list OR its depiction on the map, should make both name and depiction turn a different color. All the names and paths have logical IDs/classes on them already.

这是一个我的代码的小提琴(这是一个可怕的程序混乱,所以请原谅我。)

Here's a fiddle with my code. (It's a horrible procedural mess at the moment, so please forgive me.)

jQuery的事件功能不要在SVG上工作,虽然我知道有一个jQuery插件可以帮助,但我认为这将是一个很好的机会,使用更大比例的香草Javascript比我习惯。

jQuery's event functions don't work on SVG, and though I know there's a jQuery plugin that supposedly helps, I thought this would be a good opportunity to use a larger proportion of vanilla Javascript than I'm used to.

代码最相关的部分是Javascript的第46到69行的 makeMapInteractive 函数:

The most relevant part of the code is the makeMapInteractive function on lines 46 through 69 of the Javascript:

function makeMapInteractive(provinces) {

    for(var province in provinces) { // Iterate over every state/province code
        var $HTMLtargets = $('ul.provinces li.' + province);
        var $SVGtargets = $('path#{0}, g#{0} path'.format(province));
        var $allTargets = $HTMLtargets.add($SVGtargets);

        // I tried it first with $().each(); when that didn't work,
        // I commented it out and tried without it. Neither one works.

        /* $allTargets.each(function() {
            this.addEventListener('mouseover', function(e) {
                console.log(e);
                $HTMLtargets.css('color', '#990000');
                $SVGtargets.attr('fill', '#990000');
            }, false)
        }); */

        for(var i = 0; i < $allTargets.length; i++) {
            $allTargets.get(i).addEventListener('mouseover', function(e) {
                $HTMLtargets.css('color', '#990000');
                $SVGtargets.attr('fill', '#990000');
            }, false);
        }
    }
}

告诉它要做的是向每个元素添加一个鼠标悬停侦听器,这触发了该元素所在省份中涉及的所有元素的更改。

What I'm trying to tell it to do is to add a mouseover listener to every element, that triggers a change on all elements involved in that element's province.

实际发生的是将鼠标悬停在任何东西上在整个页面上触发最后一个事件侦听器,一个为怀俄明添加。这就像当我更改 $ allTargets 变量时,它将所有先前添加的监听器更改为新值中包含的元素。但是我看不到这样的事情,因为我将事件监听器应用于该变量中的DOM元素,而不是jQuery对象本身。

What actually happens is that hovering over anything on the whole page triggers the very last event listener added, the one for Wyoming. It's like when I change the $allTargets variable, it changes all the previously-added listeners to the elements contained in its new value. But I can't see how that's happening, since I'm applying the event listeners to the DOM elements inside that variable, not the jQuery object itself.

有人可以解释这里正在发生什么?我知道我在这里使用jQuery,但是我希望答案不要超过我已经在使用;

Can someone explain exactly what is going on here? I know I'm using jQuery a bit here, but I'd like the answer to use no more than I'm already using; it's my vanilla Javascript skill that needs increasing.

推荐答案

问题是您的 $ HTMLtargets $ $ SVGtargets 变量不是你希望他们在你的事件处理程序回调中,因为事件触发(稍后),你的外部 for 循环已经完成,因此这两个变量处于其结束值。

The problem is that your $HTMLtargets and $SVGtargets variables are not what you want them to be inside your event handler callback because when the event fires (sometime later), your outer for loop has already finished and thus those two variables are on their ending value.

您将需要一个关闭来为每个事件处理程序分别捕获这些变量。这是一种方法:

You will need a closure to capture those variables separately for each event handler. Here's one way to do that:

    // create closure to freeze the target variables
    (function(hTargets, sTargets) {
        for(var i = 0; i < $allTargets.length; i++) {
            $allTargets.get(i).addEventListener('mouseover', function(e) {
                hTargets.css('color', '#990000');
                sTargets.attr('fill', '#990000');
            }, false);
        }
    })($HTMLtargets, $SVGtargets);

FYI,我更改了封闭中变量的名称,使其更明显发生了什么。不需要将参数的名称更改为立即执行的函数表达式,因为它们将仅覆盖以前定义的函数表达式,但我认为更改名称时会发生什么更清楚。

FYI, I changed the name of the variables inside the closure to make it more obvious what was happening. It is not required to change the name of the arguments to the immediately executing function expression as they will just override the previously defined ones, but I think it's clearer what is happening if you change the names.

这篇关于为什么当我在一个循环中添加一堆事件监听器时,每个元素是否触发最后添加的侦听器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆