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

aiazj4mn  于 2022-12-10  发布在  Java
关注(0)|答案(9)|浏览(171)

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

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

wgxvkvu91#

由于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
          });
      }
baubqpgj

baubqpgj2#

新的YT.Player的第一个参数需要是HTML元素的id(例如DIV),该元素将被替换为视频的iframe。当您对这两个对象使用'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 (EDIT:更改为正确的链接)

jv2fixgn

jv2fixgn3#

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();
tp5buhyn

tp5buhyn4#

我有一个更广泛的问题,归结为这个相同的问题。我的要求是写一个JS类来管理一个或多个(数字可以从1到无穷大)视频嵌入。后端系统是ExpressionEngine主要目标是建立一个分析框架,将个人数据推送到我们的Adobe Analytics平台。这里显示的只是发挥作用的部分,它可以从这里扩展很多。
CMS允许编辑在页面上创建模块来呈现视频。每个模块一个视频。每个模块基本上是通过Bootstrap 3排列的HTML的一部分(与这个答案无关)。
相关的HTML如下所示:

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

显示“{innov_mod_ytplayer:id}”的部分是来自CMS的YouTube视频ID。这允许每个嵌入项目有一个唯一的ID。这在后面很重要。
在这下面,我再渲染出来:

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

你也会在这里看到一些ExpressionEngine模板标签--这些只是YouTube上的视频ID和视频标题。要复制这些,你当然需要更改它们。
这样做的目的是允许我为每个新嵌入的视频使用新代码动态更新单个全局回调函数。这个回调将包含对我的类的示例的调用。你需要这些try/catch块,因为它会对所有“其他”嵌入抛出一个误报错误,除了它“现在”实际执行的嵌入--记住这个脚本对页面上的每个嵌入都运行一次。这些错误是预期的,实际上不会造成任何问题,因此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更容易阅读,因为它对我可用,所以我使用它。

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

其他几点注意事项:
一旦解决了主要的全局回调问题,就很容易在类示例中保持作用域。只需添加.bind()。例如:

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

您可能还会看到:

var _this = this;

这样示例的“this”作用域就不会意外丢失。也许没有必要,但这是我多年来一直采用的惯例。
无论如何,我已经为此工作了一个星期了,我想我应该与SO社区分享它,因为很明显,从我寻找答案,很多其他人也一直在寻找解决方案。

jhkqcmku

jhkqcmku5#

我在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 = []
    }
  }
}
mitkmikd

mitkmikd6#

我所做的加载多个视频是破坏iframe当我点击视频外(你可以使用你想要的事件),然后我再次创建div,这样你就可以重用另一个视频ID的div

zzoitvuj

zzoitvuj7#

<iframe title="YouTube video player" src="https:YOUR CHANNEL Full Link" width="560" height="315" frameborder="0" allowfullscreen="allowfullscreen"></iframe>
7uhlpewt

7uhlpewt8#

作为对瓦迪姆回答的补充,以下内容对我的事件很有效:

const iframes = [{id: 'hello'},...];
const inOnReadyScope = "I can be accessed by onPlayerReady"

function onYouTubeIframeAPIReady() {
  for (let i = 0; i < iframes.length; i++) {
    const player = new YT.Player(iframe.id, {
      events {
        onReady: onPlayerReady
      }
    }
    function onPlayerReady(event){
      event.target.setVolume(0);
      console.log(inOnReadyScope)
      // use anything on event
    }
  }
}
dauxcl2d

dauxcl2d9#

<script type="text/javascript">

    $(document).ready(function () {

        $(".youtube-player").each(function () {
            var playerid = $(this).attr("id");
            setTimeout(function () {
                onYouTubeIframeAPIReady2(playerid);
            }, 2000);
        });

    });

    function onYouTubeIframeAPIReady2(PlayerID) {

        var ctrlq = document.getElementById(PlayerID);
        console.log(ctrlq);
        var player = new YT.Player(PlayerID, {
            height: ctrlq.dataset.height,
            width: ctrlq.dataset.width,
            events: {
                'onReady': function (e) {
                    e.target.cueVideoById({
                        videoId: ctrlq.dataset.video,
                        startSeconds: ctrlq.dataset.startseconds,
                        endSeconds: ctrlq.dataset.endseconds
                    });
                }
            }
        });
    }
</script>

相关问题