具有动态绑定内容的自调用函数范围

时间:2014-10-10 14:08:39

标签: javascript jquery

我已将JavaScript包装在一个自我调用函数中,以保持所有内容。但是,我遇到了一个问题,即动态构建的链接会返回错误"功能未定义"当他们被点击时。让我包括我的相关代码:

(function(window, document, $) {

    function buildChapterList() {
        for(var i=0; i<Object.keys(theChapterCues).length; i++) {
            chapterListHTML = "<li><a class='fun-blue' href='javascript:void(0)' onClick=\"skipToChapter('"+ i +"')\">"+ theChapterCues[i]["title"] +"</a></li>";
            $(chapterListHTML).appendTo("ul#chapter-list");
            $("body").bind("DOMNodeInserted", function() {
                $(this).find('#chapter-list li').first().addClass("active");
            });
        }
    }
    function skipToChapter(theChapter) {
        if (theChapter == 0) {
            theVideo.currentTime=0;
        } else {
            var thisChapterStart = parseInt(cues[theChapter]["chapterStart"]+1);
            theVideo.currentTime=thisChapterStart/frameRate;
        }
    }

}(this, this.document, this.jQuery));

点击其中一个生成的链接时,我收到以下错误:

未捕获的ReferenceError:未定义skipToChapter

我在范围上遗漏了什么吗?这是一个约束性问题吗?任何建议将不胜感激。谢谢!

2 个答案:

答案 0 :(得分:3)

skipToChapter函数不在全局范围内,因此无法从内联单击处理程序调用。相反,您应该在构建链接时以一种不显眼的方式分配单击处理程序,如下所示。如果您这样分配,那么skipToChapter就在范围内,您不必将其设为全局,并且您不需要不受欢迎的内联事件处理程序。

function buildChapterList() {
    for(var i=0; i<Object.keys(theChapterCues).length; i++) {
        chapterListHTML = $("<li><a class='fun-blue' href='javascript:void(0)'>"+ theChapterCues[i]["title"] +"</a></li>");
        (function(i){
            chapterListHTML.find('a').click(skipToChapter.bind(this, i));
        })(i);
        chapterListHTML.appendTo("ul#chapter-list");
        $("body").bind("DOMNodeInserted", function() {
            $(this).find('#chapter-list li').first().addClass("active");
        });
    }
}

答案 1 :(得分:2)

skipToChapter函数仅在外部匿名函数中可见。您可以在此处阅读有关Javascript范围的信息:http://robertnyman.com/2008/10/09/explaining-javascript-scope-and-closures/

解决问题的快速而肮脏的方法是在匿名函数之外定义skipToChapter或作为窗口对象的成员。

例如:

window.skipToChapter = function(theChapter) {
    if (theChapter == 0) {
        theVideo.currentTime=0;
    } else {
        var thisChapterStart = parseInt(cues[theChapter]["chapterStart"]+1);
        theVideo.currentTime=thisChapterStart/frameRate;
    }
}

但是,请注意,这不是将函数绑定到事件的最佳做法,因为它使skipToChapter全局并使用内联事件处理程序(http://robertnyman.com/2008/11/20/why-inline-css-and-javascript-code-is-such-a-bad-thing/)。

更好的方法是:

function buildChapterList() {
    for(var i=0; i<Object.keys(theChapterCues).length; i++) {
        chapterListHTML = "<li><a class='fun-blue' href='javascript:void(0)' data-index='" + i + "'>"+ theChapterCues[i]["title"] +"</a></li>";
        var $chapterListHTML = $(chapterListHTML);
        $chapterListHTML.appendTo("ul#chapter-list");
        $chapterListHTML.find('a').click(skipToChapter);
        $("body").bind("DOMNodeInserted", function() {
            $(this).find('#chapter-list li').first().addClass("active");
        });
    }
}
function skipToChapter() {
    var theChapter = $(this).data('index');
    if (theChapter == 0) {
        theVideo.currentTime=0;
    } else {
        var thisChapterStart = parseInt(cues[theChapter]["chapterStart"]+1);
        theVideo.currentTime=thisChapterStart/frameRate;
    }
}

阅读此答案,了解有关使用jQuery进行事件绑定的更多信息:Event binding on dynamically created elements?