2014-10-10 87 views
0

我已将自己的JavaScript包装在自调用函数中以保持所有内容。 Hoever,我遇到了一个问题,即我的链接动态构建,在点击时返回一个错误“Function not defined”。让我有我的相关代码:具有动态绑定内容的自调用函数范围

(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没有定义

?这是一个有约束力的问题?任何建议将不胜感激。谢谢!

+0

是的,你的功能只存在于你的匿名范围内。你需要在全局范围内使用它,或者找到另一种绑定事件的方法(如果你可以提供小提琴,会更容易找到另一种方法) – 2014-10-10 14:16:12

回答

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

阅读这个答案的详细信息,事件绑定在dinamically创建的元素,用jQuery:Event binding on dynamically created elements?

+0

这对我有效,但不能将其标记为答案。你能再详细说明为什么会发生这种情况吗?为什么这会修复它或者指向我可以阅读的文章? – Yuschick 2014-10-10 14:19:10

+3

-1使用全局变量和内联处理函数。 – Bergi 2014-10-10 14:29:15

+0

我的'全局'变量都包含在我的匿名函数中,只是没有包含在我的原始文章中的代码中。我现在正在学习更好的替代内联处理程序。所以学习新事物的道德准则+1。 – Yuschick 2014-10-10 14:45:07

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"); 
     }); 
    } 
} 
+0

谢谢你的解释。这是一个非常干净的解决方案,看起来像一个不断前进的良好实践。 – Yuschick 2014-10-10 14:42:34

+0

该解决方案在循环内定义了一个函数,这不是一个好习惯。 – ncardeli 2014-10-10 14:52:07

+0

循环中的函数是不好的做法?来自使用全局和内联事件处理程序发布答案的人.....好吧。 – MrCode 2014-10-10 14:54:57