jQuery:使用闭包修复点击for循环中的函数绑定

时间:2012-10-28 02:57:34

标签: javascript jquery arrays object closures

我被困在这里,任何暗示都会很好 我有一个Objects对象[]和一个divnames []数组。我的对象上有play()和stop()等函数。对象及其功能在多种情况下进行了测试,它们正在运行。现在我尝试迭代divnames []并将适当对象[]的动作分配给mouseover,mouseout和click。
有一个闭包问题,我修复了一个解决方案,我在StackOverflow上的另一个线程中找到了。这样可行。但剩下的问题是鼠标悬停等操作未分配给稍后加载的div。他们正在从一开始就处理页面上的对象 这就是我所拥有的:

$(function(){
    for (var i=0, len=divnames.length; i<len; i++) {
        if(divnames[i]){
            (function( ) { // anonymous function to fix closures
                var index = i; // also needed to fix closures
                $('#'+divnames[index]).on("click", function() {
                    objects[index].play();
                    loadContent(divnames[index]+".php");
                });
            })( ); // direct function execution to fix closures
        }
    }
});

如上所述,闭包问题由两个注释行修复,将它们离开只会应用for循环的最后一次执行。就像现在一样,这是有效的 但是什么不起作用,是click函数也应该应用于匹配选择器的div,但尚未加载 但是,如果具有相同功能的代码没有在没有闭包修复的情况下在for循环内迭代,那确实有效,因为如果我理解正确的话,那就是预期的.on()行为。

那么我如何才能获得所需的功能?

感谢您的提前时间。

---- ----编辑

要求的其他信息:

var divnames = [];
divnames[0] = "home";
divnames[1] = "about";
divnames[2] = "projects";

function SpriteAnim (options) {
var timerId = 0; 
    var i = 0;
    this.status = 0;
this.init = function () {
    var element = document.getElementById(options.elementId);
    element.style.width = options.width + "px";
    element.style.height = options.height + "px";
    element.style.backgroundRepeat = "no-repeat";
    element.style.backgroundImage = "url(" + options.sprite + ")";
};
this.showFrame = function (which) {
    if (which < options.frames) {
                    i = which;
        element = document.getElementById(options.elementId);
        element.style.backgroundPosition = "0px -" + which * options.height + "px";
    }
};
this.play = function () {
            this.status = 2;
    timerId = setInterval(function () {
        if (i < (options.frames - 1)) {
                            i++;
            element = document.getElementById(options.elementId);
            element.style.backgroundPosition = "0px -" + i * options.height + "px";
                    } else {
                        clearInterval(timerId);
                        this.status = 1;
                    }
    }, 100);
};
}

正如您可能已经猜到的那样,objects []数组在对象[0],对象[1],对象[2]中包含3个SpriteAnim对象。

objects[0] = new SpriteAnim({
    width: 7,
    height: 7,
    frames: 8,
    sprite: "myanim1.png",
    elementId: "anim0"
});
objects[1] = new SpriteAnim({
    width: 7,
    height: 7,
    frames: 8,
    sprite: "myanim1.png",
    elementId: "anim1"
});
objects[2] = new SpriteAnim({
    width: 7,
    height: 7,
    frames: 8,
    sprite: "myanim2.png",
    elementId: "anim2"
});

2 个答案:

答案 0 :(得分:4)

您需要使用事件委派,并在父元素而不是元素本身上侦听这些事件。这样,如果稍后添加新元素,则无需重新绑定它们。

$("#buttons").on("click", ".button", function(){
    console.log("You clicked on a .button element.");
});

在这种情况下,我们绑定#buttons上的click事件,但仅当调用元素与选择器.button匹配时。你的标记将是这样的:

<div id="buttons">
    <a class="button">Foo</a>
    <a class="button">Bar</a>
</div>

当任何.button元素发生咔嗒声,并且气泡到#buttons父元素时,它将被拦截并且处理程序将被触发。

答案 1 :(得分:1)

这是因为索引是在绑定语句之外声明的。当点击进入该调用时,它不知道[index]是什么对象。

如果你想保持相同的结构,请像这样重写你的功能:

$(function(){
    for (var i=0, len=divnames.length; i<len; i++) {
        if(divnames[i]){
            (function( ) { // anonymous function to fix closures
                var index = i; // also needed to fix closures
                $('#'+divnames[index]).on("click", function(e) {
                    switch ($(e.id).attr('name')){
                        case 'home':
                            objects[0].play();
                            loadContent('home.php');
                            break;
                        case 'about':
                        // do same
                        case 'projects':
                        // do same
                        default:
                            break;
                    }
                });
            })( ); // direct function execution to fix closures
        }
    }
});

实际上,你应该这样做:

$(document).on('click','div[name=home],div[name=projects],div[name=about]', function(){
    var name = $(this).attr('name');
    switch (name){
        case 'home':
            objects[0].play();
            break;
            // and so on
    }
    loadContent(name + '.php');
});

编辑:

当你点击你的div时,这就是它所知道的全部:

objects[index].play();
loadContent(divnames[index]+".php");