2

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

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

jQuery 的事件函数在 SVG 上不起作用,虽然我知道有一个 jQuery 插件可能会有所帮助,但我认为这将是一个使用比我习惯的更大比例的 vanilla Javascript 的好机会。

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

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

我试图告诉它做的是为每个元素添加一个鼠标悬停侦听器,这会触发该元素所在省涉及的所有元素的更改。

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

有人可以准确解释这里发生了什么吗?我知道我在这里使用了一点 jQuery,但我希望答案不要超过我已经在使用的;这是我需要提高的普通 Javascript 技能。

4

1 回答 1

6

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

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

    // 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);

仅供参考,我更改了闭包内变量的名称,以使发生的事情更加明显。不需要将参数的名称更改为立即执行的函数表达式,因为它们只会覆盖先前定义的参数,但我认为如果更改名称会更清楚发生了什么。

于 2013-09-18T19:43:08.307 回答