19

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

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

8 回答 8

30

由于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
          });
      }
于 2013-09-21T19:37:46.253 回答
24

new YT.Player 的第一个参数需要是要替换为视频 iframe 的 HTML 元素(fe 一个 DIV)的 id。当您对这两个对象都使用“播放器”时,您会将两者加载到同一个元素中。

<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 (编辑:更改为正确的链接)

于 2013-06-09T22:41:36.523 回答
3

的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();
于 2018-08-10T15:03:23.837 回答
2

我有一个更广泛的问题,归结为同样的问题。我的要求是编写一个 JS 类来管理一个或多个(数量可以从 1 到无穷大不等)视频嵌入。后端系统是 ExpressionEngine(但在这里无关紧要)。主要目标是建立一个分析框架,将个人数据推送到我们的 Adob​​e 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 等效于 jQuery 的扩展方法)我只是发现 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 社区分享它,因为从我寻找答案中可以清楚地看出,很多其他人也在寻找解决方案。

于 2017-03-17T22:48:57.353 回答
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 = []
    }
  }
}
于 2016-07-09T19:08:09.967 回答
0

我加载多个视频所做的是在我在视频外部单击时破坏 iframe(您可以使用所需的事件)然后我再次创建了 div,这样您就可以使用另一个视频 ID 重用 div

于 2020-07-03T16:15:31.210 回答
0
<iframe title="YouTube video player" src="https:YOUR CHANNEL Full Link" width="560" height="315" frameborder="0" allowfullscreen="allowfullscreen"></iframe>
于 2022-02-09T18:44:34.760 回答
-2
<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>
于 2021-08-12T12:07:16.433 回答