Je dois charger plus d'une vidéo avec l'API de youtube. C'est la première fois que je l'utilise, donc je ne suis pas sûr de ce que je fais mal, mais voici ce que j'essaie
var player;
var player2;
function onYouTubePlayerAPIReady() {
player = new YT.Player('player', {
videoId: 'hdy78ehsjdi'
});
player2 = new YT.Player('player', {
videoId: '81hdjskilct'
});
}
Puisque la fonction onYouTubeIframeAPIReady
est supposée être appelée une seule fois, l'approche suivante pourrait être utilisée:
initialiser et sauvegarder les informations du lecteur vidéo (ControlId,width,height,VideoId
) dans le tableau
appelez la fonction onYouTubeIframeAPIReady
pour créer tous les lecteurs vidéo
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
});
}
Le premier paramètre de new YT.Player doit être l'id de l'élément HTML (par exemple, un DIV) à remplacer par un iframe de la vidéo . Lorsque vous utilisez 'player' pour ces deux objets, vous allez charger les deux dans le même élément.
<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>
Les paramètres des fonctions sont décrits dans la documentation de l'API Youtube:
https://developers.google.com/youtube/iframe_api_reference#Loading_a_Video_Player (EDIT: modifié sur le lien de droite)
J'ai eu un problème plus vaste qui se résumait à ce même problème. Les exigences que j'avais étaient d'écrire une classe JS pour gérer un ou plusieurs (le nombre peut varier de 1 à l'infini) intègre vidéo. Le système de base est ExpressionEngine (mais ce n'est pas pertinent ici). L'objectif principal était de mettre en place un cadre d'analyse qui transfère des données individuelles vers notre plateforme Adobe Analytics. On montre ici simplement la partie qui donne le compte de jeu, elle peut être beaucoup développée à partir d’ici.
Le CMS permet aux éditeurs de créer sur la page des modules présentant une vidéo. Une vidéo par module. Chaque module est fondamentalement une section de HTML organisée via Bootstrap 3 (non pertinent pour cette réponse).
Le code HTML approprié ressemble à ceci:
<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>
La partie intitulée "{innov_mod_ytplayer: id}" correspond à l'identifiant de la vidéo YouTube de notre CMS. Cela permet d’obtenir un identifiant unique pour chaque élément intégré. Ceci est important plus tard.
Ci-dessous, je rendrai ensuite:
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){}
})();
Vous verrez également quelques balises de modèle ExpressionEngine ici - il s’agit uniquement de l’ID de la vidéo et du titre de la vidéo de YouTube. Pour reproduire cela, vous devrez bien sûr les modifier.
Cela me permet de mettre à jour dynamiquement le rappel global unique avec un nouveau code pour chaque vidéo intégrée. En fin de compte, ce rappel contiendra des appels à leurs propres instances de ma classe. Vous avez besoin de ces blocs try/catch, car il génère une erreur fausse-positive pour tous les "autres" incorporés, à l'exception de celui qu'il exécute "en ce moment". Les erreurs sont attendues et ne posent en réalité aucun problème, donc try/catch les supprime.
À l'aide de la balise de modèle CMS, je crée chaque instance en fonction de l'ID de vidéo YouTube. Je rencontrerais un problème si quelqu'un ajoutait le même module vidéo plusieurs fois, mais il s'agit d'un problème commercial facile à gérer, car cela n'est pas censé se produire. Cela me permet d'instancier plusieurs fois des instances uniques de ma classe pour chaque vidéo.
La partie critique de ce script est basée sur cette réponse extrêmement utile SO: Ajouter du code à une fonction javascript par programme
Voici la classe actuelle. C'est surtout commenté ... Nous utilisons jQuery, vous verrez donc une utilisation importante ici dans la méthode $ .extend (). J'utilise cela comme une commodité dans la méthode du constructeur de classe, mais vous pouvez le faire avec Vanilla JS aussi ( équivalent JavaScript de la méthode extend de jQuery ). utilise le.
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');
}
}
}
}
Quelques autres notes:
Il est facile de garder la portée dans l'instance de classe une fois que vous avez résolu le principal problème de rappel global. Vous devez juste ajouter .bind (). Par exemple:
'onReady': _this.onPlayerReady.bind(_this)
Vous pourriez aussi voir:
var _this = this;
Cela signifie que l'étendue "ceci" de l'instance n'est pas perdue accidentellement. Peut-être pas nécessaire, mais c'est une convention que j'ai adoptée au fil des ans.
Quoi qu'il en soit, je travaille sur ce sujet depuis une semaine maintenant et je pense que je le partagerais avec la communauté SO puisqu’il ressort clairement de ma recherche de réponses que beaucoup d’autres ont également cherché des solutions à ce problème.
J'avais besoin de cette même chose dans React. En développant la réponse de Vadim, vous pouvez faire quelque chose comme ceci et les ajouter à un objet, puis créer le joueur si vous ne savez pas à quoi ressemblera l’éventail de joueurs auparavant.
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 = []
}
}
}
Le HTML
<div data-id="youtubevideoidhere" class="video"></div>
<div data-id="youtubevideoidhere" class="video"></div>
<div data-id="youtubevideoidhere" class="video"></div>
Le JS pour les vidéos
// 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;
})();
Et puis, créez des vidéos comme celle-ci
var videos = new Videos();
$('.video').each( function () {
videos.add( $(this) );
})
videos.loadApi();