【问题标题】:Loading Youtube Iframe API with RequireJS使用 RequireJS 加载 Youtube Iframe API
【发布时间】:2012-10-11 15:59:22
【问题描述】:

我正在尝试在 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

如果我不使用异步插件,对象 YT 或其函数是未定义的,如果我下载 API 代码也会发生同样的情况。如果我将脚本标记放在 html 文件的头标记中,有时会加载 API。这一切都是意料之中的,但我不明白,因为异步插件失败了。

感谢您的关注和帮助:)

【问题讨论】:

    标签: javascript youtube-api requirejs


    【解决方案1】:

    我不熟悉 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;
    });
    

    【讨论】:

    • 这很好用,谢谢。虽然我不喜欢定义全局函数,但我认为它是满足谷歌图书馆奇怪需求的唯一解决方案。
    【解决方案2】:

    经过一些研究并且对其他答案不满意,我已经通过扩展 require async!插件支持命名回调,然后确保模块代码仅在 API 完全加载后执行。

    核心问题似乎是,YouTube Iframe API 不允许您配置回调的名称,而是将其指定为“onYouTubeIframeAPIReady”,这是我们对异步插件的小升级解决的问题。此解决方案仍然使用全局 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

    升级应该完全向后兼容,即 为什么有这个相当丑陋的未定义作为第一个插件参数。任何关于如何使它更漂亮和简单的想法都非常受欢迎。

    【讨论】:

      【解决方案3】:

      第 1 步:要求 YouTube 不带扩展名

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

      第 2 步:将 onYouTubeIframeAPIReady 函数附加到窗口对象

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

      第 3 步:异步加载脚本

      require(['youtube']);

      这将触发您的onYouTubeIframeAPIReady 功能,您就开始营业了

      【讨论】:

        【解决方案4】:

        另一个使用 require 加载外部 javascript 并在加载 javascript 时发出带有上下文的 jQuery 承诺回调的选项。

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

        【讨论】:

          【解决方案5】:

          配置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({...});
          });
          

          【讨论】:

          • 由于 YT.Player 未定义而随机失败。尝试将导出:'YT' 更改为导出:'YT.Player',但似乎没有帮助
          • 这正是我最初设置的方式,但仍然让 YT.Player 随机失败,如 @zhopon。
          猜你喜欢
          • 2014-01-26
          • 2013-10-24
          • 2014-07-06
          • 1970-01-01
          • 1970-01-01
          • 2015-06-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多