使用RequireJS加载Youtube Iframe API

8
我正在尝试在使用Require JS定义的模块中使用Youtube Iframe API。由于该API是异步加载并在加载后调用函数,因此我使用了一个名为“async”的requireJS插件,该插件之前与google maps api一起使用过。
然而,这一次出现了问题。我的模块以以下方式开始: define(['text!fmwk/widgets/video/video.html','fmwk/utils/browser','async!http://www.youtube.com/iframe_api'], function (videoTpl,root) { ... }); Chrome控制台会报错: Uncaught Error: Load timeout for modules: async!http://www.youtube.com/iframe_api_unnormalized3,async!http://www.youtube.com/iframe_api http://requirejs.org/docs/errors.html#timeout 如果我不使用async插件,则YT对象或其函数未定义,如果我下载API代码也是同样的情况。如果将脚本标签放在html文件的head标签中,有时会加载API。所有这些都是预期的,但我不理解为什么async插件会失败。
谢谢您的关注和帮助 :)
5个回答

14

我对async的requireJS插件不太熟悉,但是这里有一些示例代码(摘自YouTube Direct Lite),可以在名为player的requireJS模块中异步加载iframe API。它使用jQuery来实际处理库的加载。

define(['jquery'], function($) {
  var player = {
    playVideo: function(container, videoId) {
      if (typeof(YT) == 'undefined' || typeof(YT.Player) == 'undefined') {
        window.onYouTubeIframeAPIReady = function() {
          player.loadPlayer(container, videoId);
        };

        $.getScript('//www.youtube.com/iframe_api');
      } else {
        player.loadPlayer(container, videoId);
      }
    },

    loadPlayer: function(container, videoId) {
      new YT.Player(container, {
        videoId: videoId,
        width: 356,
        height: 200,
        // For a list of all parameters, see:
        // https://developers.google.com/youtube/player_parameters
        playerVars: {
          autoplay: 1,
          controls: 0,
          modestbranding: 1,
          rel: 0,
          showinfo: 0
        }
      });
    }
  };

  return player;
});

这个完美地运作了,谢谢。虽然我不喜欢定义全局函数,但我想这可能是解决谷歌库奇怪需求的唯一方法。 - dgnin

6
经过一些研究并对其他答案不满意后,我通过扩展 require async! 插件来解决这个确切的问题以及可能出现的其他问题,使模块代码只有在 API 完全加载后才会被执行。核心问题似乎是,YouTube Iframe API 不允许您配置回调名称,但要求它为“onYouTubeIframeAPIReady”,我们对 async 插件进行了小升级来解决这个问题。这个解决方案仍然使用全局 window.YT,但可以不用 jQuery 来运作。
require(
    ['async!//www.youtube.com/iframe_api!undefined:onYouTubeIframeAPIReady'],
    function() { 

        // this codes executes your code once YouTube Iframe API is loaded and ready
        player = new YT.Player({ ... });

    }
);

也适用于内联的require调用:

define([], function () {
    // .. some of your other code here

    require(['async!//www.youtube.com/iframe_api!undefined:onYouTubeIframeAPIReady'],      function () {

        // this codes executes your code once YouTube Iframe API is loaded and ready
        player = new YT.Player({ ... });

    });
});

在我看来,这段代码比以前任何时候都更加清晰。另外,通过在最后一刻加载API所带来的性能提升非常巨大,特别是与数十个玩家一起使用时。当然,API只会被加载一次并像往常一样被缓存。

已升级!async插件:https://github.com/mhrisse/requirejs-plugins/blob/master/src/async.js

已提出升级!async插件的请求:https://github.com/millermedeiros/requirejs-plugins/pull/39

升级应该完全向后兼容,这就是为什么第一个插件参数是未定义的原因。如果有任何想法使其更加美观和简单,欢迎提出。


6
第一步:不使用扩展程序即可下载YouTube视频。

require.config({
  ...
  youtube: '//www.youtube.com/iframe_api?noext',
  ...
})

步骤2:将onYouTubeIframeAPIReady函数附加到window对象上。

var player;
window.onYouTubeIframeAPIReady = function(){
  player = new YT.Player('player', {
    height: '390',
    width: '640',
    videoId: 'M7lc1UVf-VE',
  });
};

步骤三:异步加载脚本

require(['youtube']);

这将触发您的onYouTubeIframeAPIReady函数,然后您就可以开始了。

3

配置requirejs

require.config({
    paths: {
        // Notice the ?noext query parameter. It is added to prevent from requirejs to add .js extension
        youTubeIFrame: 'https://www.youtube.com/iframe_api?noext'
    },
    shim: {
        youTubeIFrame: {
            // Now requirejs expects a YT global variable to be initialized
            // http://requirejs.org/docs/api.html#config-shim
            exports: 'YT'
        }
    }
 });

使用方法

require(['youTubeIFrame'], function(YT) {
    // Here YT will be already available because requirejs waited for this global variable to be initialized.
    // No need to define a global function onYouTubeIframeAPIReady
    new YT.Player({...});
});

1
随机失败,因为YT.Player未定义。尝试将exports更改为“YT.Player”,但似乎没有帮助。 - zhopon
这正是我最初设置的方式,但仍然会出现YT.Player随机失败,就像@zhopon一样。 - Blake Petersen

3

另一种选项是使用require加载外部javascript,并在javascript加载完成后发出带有上下文的jQuery promise回调。

this.initVideo = function emebdvideo(){
        //Have we already loaded the youtube iframe API?
        if(typeof YT === 'undefined' || typeof YT.Player == 'undefined'){
            var loaded = this.loadYTapi();
            loaded.done(this.embedVideo);
        }else{
            this.embedVideo();
        }

};

this.loadYTapi = function loadYTapi(){

        var dfd = $.Deferred(),
        context = this;

        //Load youtube js with require
        require(['https://www.youtube.com/iframe_api'], function(){
            window.onYouTubeIframeAPIReady = function() {

                //Resolve with context
                dfd.resolveWith(context);
            };
        });

        return dfd;
};

this.embedVideo = function embedVideo(){

        var youtubeId = 'youtube-id';
        var player = new YT.Player('player', {
          height: '390',
          width: '640',
          videoId: youtubeId,
          events: {
            'onReady': this.onPlayerReady,
            'onStateChange': this.onPlayerStateChange
          }
        });
};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接