使用youtube api加载多个视频播放器

时间:2013-06-09 18:38:55

标签: javascript youtube youtube-api

我需要使用youtube的API加载多个视频。这是我第一次使用它,所以我不确定我做错了什么,但这就是我正在尝试的:

  var player;
  var player2;
  function onYouTubePlayerAPIReady() {
    player = new YT.Player('player', {
      videoId: 'hdy78ehsjdi'
    });
    player2 = new YT.Player('player', {
      videoId: '81hdjskilct'
    });
  }

6 个答案:

答案 0 :(得分:24)

由于onYouTubeIframeAPIReady函数只能调用一次,因此可以使用以下方法:

  • 初始化并保存视频播放器信息 数组中的{ControlId,width,height,VideoId}

  • 调用onYouTubeIframeAPIReady函数创建所有视频 球员

实施例

var playerInfoList = [{id:'player',height:'390',width:'640',videoId:'M7lc1UVf-VE'},{id:'player1',height:'390',width:'640',videoId:'M7lc1UVf-VE'}];

      function onYouTubeIframeAPIReady() {
        if(typeof playerInfoList === 'undefined')
           return; 

        for(var i = 0; i < playerInfoList.length;i++) {
          var curplayer = createPlayer(playerInfoList[i]);
        }   
      }
      function createPlayer(playerInfo) {
          return new YT.Player(playerInfo.id, {
             height: playerInfo.height,
             width: playerInfo.width,
             videoId: playerInfo.videoId
          });
      }

答案 1 :(得分:21)

新YT.Player的第一个参数需要是要用视频iframe替换的HTML元素(例如,DIV)的id。 当你为这两个对象使用'player'时,你将把它们加载到同一个元素中。

<div id="ytplayer1"></div>
<div id="ytplayer2"></div>

<script>
  var player;
  var player2;
  function onYouTubePlayerAPIReady() {
    player = new YT.Player('ytplayer1', {
      height: '390',
      width: '640',
      videoId: 'hdy78ehsjdi'
    });
    player2 = new YT.Player('ytplayer2', {
      height: '390',
      width: '640',
      videoId: '81hdjskilct'
    });
  }
</script>

Youtube API文档中描述了函数的参数:
https://developers.google.com/youtube/iframe_api_reference#Loading_a_Video_Player(编辑:更改为右侧链接)

答案 2 :(得分:2)

我有一个更广泛的问题归结为同样的问题。我的要求是编写一个JS类来管理一个或多个(数字可以从1到无穷大)视频嵌入。后端系统是ExpressionEngine(但这里不相关)。主要目标是建立一个分析框架,将个人数据推送到我们的Adobe Analytics平台。这里显示的只是提供播放次数的部分,它可以从这里扩展很多。

CMS允许编辑者在显示视频的页面上创建模块。每个模块一个视频。每个模块基本上都是通过Bootstrap 3排列的HTML部分(与此答案无关)。

相关的HTML如下所示:

&#13;
&#13;
<div id="js_youTubeContainer_{innov_mod_ytplayer:id}" class="embed-responsive embed-responsive-16by9">
  <div id="js_youTubeFrame_{innov_mod_ytplayer:id}" class="embed-responsive-item"></div>
</div>
&#13;
&#13;
&#13;

部分说&#34; {innov_mod_ytplayer:id}&#34;是来自CMS的YouTube视频ID。这允许每个嵌入项目的唯一ID。这在以后很重要。

在此之下,我然后渲染出来:

&#13;
&#13;
            var innovYouTube_{innov_mod_ytplayer:id} = new Ariba.Innovations.YouTube.Class({
                'innovYouTubeVideoId': '{innov_mod_ytplayer:id}',
                'innovYouTubeVideoTitle': '{innov_mod_ytplayer:title}',
                'innovYouTubeDivId' : 'js_youTubeFrame_{innov_mod_ytplayer:id}'
            });
            innovYouTube_{innov_mod_ytplayer:id}.Init(); // And... Go!

            var onYouTubeIframeAPIReady = (function() {
                try{ //wrap this in try/catch because it actually throws errors when it runs subsequent times - this is expected as it's related to YouTube "rerunning" the function on other videos.
                    innovYouTube_{innov_mod_ytplayer:id}.config.functionCache = onYouTubeIframeAPIReady; //cache the existing global function
                    return function() {
                        try{
                            innovYouTube_{innov_mod_ytplayer:id}.onYouTubeIframeAPIReady(); //execute this instance's function
                            var newOnYouTubeIframeAPIReady = innovYouTube_{innov_mod_ytplayer:id}.config.functionCache.apply(this, arguments); //add instances to global function
                            return newOnYouTubeIframeAPIReady; //update global function
                        }catch(err){}
                    };
                }catch(err){}
            })();
&#13;
&#13;
&#13;

您也会在此处看到一些ExpressionEngine模板标签 - 这些标签只是来自YouTube的视频ID和视频标题。要复制这一点,您当然需要更改它们。

这样做可以让我使用每个新嵌入视频的新代码动态更新单个全局回调。最后,这个回调将包含对我们自己的类实例的调用。你需要那些try / catch块,因为它会为所有&#34;其他&#34;引发误报错误。嵌入除了它实际执行的那个&#34;现在&#34; - 请记住,对于页面上的每个嵌入,此脚本都会运行一次。错误是预期的,实际上没有问题,所以try / catch会抑制它们。

使用CMS模板代码,我会根据YouTube视频ID创建每个实例。如果有人多次添加相同的视频模块,我会遇到问题,但这是一个容易处理的业务问题,因为这不应该发生。这允许我为每个视频反复实例化我的类的唯一实例。

该脚本的关键部分基于这个非常有用的SO答案:Adding code to a javascript function programmatically

这是实际的课程。它主要是评论...我们使用jQuery,所以你会在$ .extend()方法中看到它的一个重要用途。我在类构造函数方法中使用它作为一个方便,但是你也可以使用vanilla JS(JavaScript equivalent of jQuery's extend method)这样做我只是觉得jQuery更容易阅读,因为我可以使用它,所以我使用它它

&#13;
&#13;
if (typeof Ariba === "undefined") { var Ariba = {}; }
if (typeof Ariba.Innovations === "undefined") { Ariba.Innovations = {}; }
if (typeof Ariba.Innovations.YouTube === "undefined") { Ariba.Innovations.YouTube = {}; }

if (typeof Ariba.Innovations.YouTube.Class === "undefined") {//this script may be embedded more than once - do this to avoid re-processing it on subsequent loads
    Ariba.Innovations.YouTube.Class = function (config) {
        this.static = {
            'ytScriptId': 'js_youtubeFrameAPI',
            'ytScriptUrl': 'https://www.youtube.com/iframe_api'
        };//static configuration.  Will overwrite any other settings with the same name
        this.config = {//optional configuration variables. Will be overridden by instance or static settings with the same name.
            'adobeAnalyticsFired': false
        };
        this.config = $.extend(true, this.config, config);//inserts (destructively!) the instance settings.
        this.config = $.extend(true, this.config, this.static);//inserts (destructively!) the static settings.
        this.config.this = this;
    };

    Ariba.Innovations.YouTube.Class.prototype.Init = function () {
        //Note: have to allow it to write it over an over because calling the API script is what makes YouTube call onYouTubeIframeAPIReady.
        //if (document.getElementById('js_youtubeFrameAPI') === null) { // don't add the script again if it already exists!
        this.config.apiScript = document.createElement('script');
        this.config.apiScript.src = 'https://www.youtube.com/iframe_api';
        this.config.apiScript.id = 'js_youtubeFrameAPI' + this.config.innovYouTubeVideoId;
        this.config.firstScriptTag = document.getElementsByTagName('script')[0];
        this.config.firstScriptTag.parentNode.insertBefore(this.config.apiScript, this.config.firstScriptTag);
        //}
        //else { console.log("iframe script already embedded", this.config.innovYouTubeVideoId); }
    }

    Ariba.Innovations.YouTube.Class.prototype.onYouTubeIframeAPIReady = function (event) {
        //console.log("onYouTubeIframeAPIReady", this.config.innovYouTubeVideoId, arguments);
        var _this = this;
        //console.log(this);
        this.config.ytPlayer = new YT.Player(this.config.innovYouTubeDivId, {
            videoId: this.config.innovYouTubeVideoId,
            events: {
                'onReady': _this.onPlayerReady.bind(_this),
                'onStateChange': _this.onPlayerStateChange.bind(_this)
            }
        });
    }

    Ariba.Innovations.YouTube.Class.prototype.onPlayerReady = function (event) {
        //console.log("onPlayerReady", this.config.innovYouTubeVideoId, event);
    }

    Ariba.Innovations.YouTube.Class.prototype.onPlayerStateChange = function (event) {
        //console.log("onPlayerStateChange", this.config.innovYouTubeVideoId, event, this);
        if (event.data === YT.PlayerState.PLAYING && !this.config.adobeAnalyticsFired) {
            //console.log("YouTube Video is PLAYING!!", this.config.innovYouTubeVideoId);
            this.config.adobeAnalyticsFired = true;
            if (typeof _satellite !== "undefined") {
                window._satellite.data.customVars.adhoc_tracker_val = "Innovations Video: " + this.config.innovYouTubeVideoTitle + " (" + this.config.innovYouTubeVideoId + ")";
                _satellite.track('adhoctrack');
            }
        }
    }
}
&#13;
&#13;
&#13;

其他几点说明:

一旦解决了主要的全局回调问题,在类实例中保持范围很容易。你只需要添加.bind()。例如:

'onReady': _this.onPlayerReady.bind(_this)

您可能还会看到:

var _this = this;

这就是&#34;这个&#34;实例的范围不会意外丢失。也许没有必要,但这是我多年来采用的惯例。

无论如何,我已经在这方面工作了一个星期,并且认为我与SO社区分享它,因为我很清楚我寻找答案很多其他人已经也在寻找解决方案。

答案 3 :(得分:1)

我在React中需要同样的东西。根据Vadim的回答,您可以执行以下操作并将其添加到对象中,然后创建播放器,如果您不知道之前玩家阵列的样子。

const YoutubeAPILoader = {
  _queue: [],
  _isLoaded: false,

  load: function (component) {
    // if the API is loaded just create the player
    if (this._isLoaded) {
      component._createPlayer()
    } else {
      this._queue.push(component)

      // load the Youtube API if this was the first component added
      if (this._queue.length === 1) {
        this._loadAPI()
      }
    }
  },

  _loadAPI: function () {
    // load the api however you like
    loadAPI('//youtube.com/player_api')

    window.onYouTubeIframeAPIReady = () => {
      this._isLoaded = true
      for (let i = this._queue.length; i--;) {
        this._queue[i]._createPlayer()
      }
      this._queue = []
    }
  }
}

答案 4 :(得分:0)

HTML

<div data-id="youtubevideoidhere" class="video"></div>
<div data-id="youtubevideoidhere" class="video"></div>
<div data-id="youtubevideoidhere" class="video"></div>

视频JS

// CREATE VIDEOS "CLASS" to handler videos
var Videos = (function() {
    // VARIABLES
    var $   = jQuery,   // The jquery
    players = [],       // players array (to coltrol players individually)
    queue   = [];       // videos queue (once api is ready, transform this into YT player)

    // Constructor
    function Videos() {}

    // METHODS
    // Add elements to queue
    Videos.prototype.add = function($video) {
        queue.push($video);
    };

    // Load YT API
    Videos.prototype.loadApi = function() {
        // jQuery get script
        $.getScript("//www.youtube.com/iframe_api", function() {
            // once loaded, create the onYouTubeIframeAPIReady function
            window.onYouTubeIframeAPIReady = function() {
                queue.forEach(function($video) {
                    // Create the YT player
                    var player = new YT.Player($video.get(0), {
                        'width': "100%",
                        'height': "100%",
                        'videoId': $video.data("id")
                    });
                    // add to players array
                    players.push(player);
                });
            };
        });
    };

    return Videos;

})();

然后创建这样的视频

var videos = new Videos();
$('.video').each( function () {
    videos.add( $(this) );
})
videos.loadApi();

答案 5 :(得分:0)

当我在视频外部单击时(我可以使用您想要的事件),我做的加载多个视频的操作破坏了iframe,然后再次创建了div,以便您可以将div与另一个视频ID重复使用