API iframe di YouTube: come controllo un player iframe già presente nell’HTML?

Voglio essere in grado di controllare i giocatori di YouTube basati su iframe. Questi giocatori saranno già in HTML, ma voglio controllarli tramite l’API JavaScript.

Ho letto la documentazione dell’API iframe che spiega come aggiungere un nuovo video alla pagina con l’API e quindi controllarlo con le funzioni del player di YouTube:

var player; function onYouTubePlayerAPIReady() { player = new YT.Player('container', { height: '390', width: '640', videoId: 'u1zgFlCw8Aw', events: { 'onReady': onPlayerReady, 'onStateChange': onPlayerStateChange } }); } 

Quel codice crea un nuovo object giocatore e lo assegna a “giocatore”, quindi lo inserisce all’interno del div #container. Quindi posso operare su “player” e chiamare playVideo() , pauseVideo() , ecc. Su di esso.

Ma voglio essere in grado di operare su giocatori iframe che sono già sulla pagina.

Potrei farlo molto facilmente con il vecchio metodo di incorporamento, con qualcosa di simile:

     player = getElementById('whateverID'); player.playVideo(); 

    Ma questo non funziona con i nuovi iframe. Come posso assegnare un object iframe già sulla pagina e quindi utilizzare le funzioni API su di esso?

    Fiddle Links: Codice sorgente – Anteprima – Versione piccola
    Aggiornamento: questa piccola funzione eseguirà il codice solo in una singola direzione. Se vuoi un supporto completo (ad esempio, ascoltatori / getter dell’evento), dai un’occhiata a Listening for Youtube Event in jQuery

    Come risultato di un’analisi approfondita del codice, ho creato una funzione: function callPlayer richiede una chiamata di funzione su qualsiasi video di YouTube con frame. Consulta il riferimento Api di YouTube per ottenere un elenco completo delle possibili chiamate di funzione. Leggi i commenti al codice sorgente per una spiegazione.

    Il 17 maggio 2012, la dimensione del codice è stata raddoppiata al fine di prendersi cura dello stato di pronto del giocatore. Se hai bisogno di una funzione compatta che non ha a che fare con lo stato di pronto del giocatore, vedi http://jsfiddle.net/8R5y6/ .

     /** * @author Rob W  * @website https://stackoverflow.com/a/7513356/938089 * @version 20131010 * @description Executes function on a framed YouTube video (see website link) * For a full list of possible functions, see: * https://developers.google.com/youtube/js_api_reference * @param String frame_id The id of (the div containing) the frame * @param String func Desired function to call, eg. "playVideo" * (Function) Function to call when the player is ready. * @param Array args (optional) List of arguments to pass to function func*/ function callPlayer(frame_id, func, args) { if (window.jQuery && frame_id instanceof jQuery) frame_id = frame_id.get(0).id; var iframe = document.getElementById(frame_id); if (iframe && iframe.tagName.toUpperCase() != 'IFRAME') { iframe = iframe.getElementsByTagName('iframe')[0]; } // When the player is not ready yet, add the event to a queue // Each frame_id is associated with an own queue. // Each queue has three possible states: // undefined = uninitialised / array = queue / 0 = ready if (!callPlayer.queue) callPlayer.queue = {}; var queue = callPlayer.queue[frame_id], domReady = document.readyState == 'complete'; if (domReady && !iframe) { // DOM is ready and iframe does not exist. Log a message window.console && console.log('callPlayer: Frame not found; id=' + frame_id); if (queue) clearInterval(queue.poller); } else if (func === 'listening') { // Sending the "listener" message to the frame, to request status updates if (iframe && iframe.contentWindow) { func = '{"event":"listening","id":' + JSON.stringify(''+frame_id) + '}'; iframe.contentWindow.postMessage(func, '*'); } } else if (!domReady || iframe && (!iframe.contentWindow || queue && !queue.ready) || (!queue || !queue.ready) && typeof func === 'function') { if (!queue) queue = callPlayer.queue[frame_id] = []; queue.push([func, args]); if (!('poller' in queue)) { // keep polling until the document and frame is ready queue.poller = setInterval(function() { callPlayer(frame_id, 'listening'); }, 250); // Add a global "message" event listener, to catch status updates: messageEvent(1, function runOnceReady(e) { if (!iframe) { iframe = document.getElementById(frame_id); if (!iframe) return; if (iframe.tagName.toUpperCase() != 'IFRAME') { iframe = iframe.getElementsByTagName('iframe')[0]; if (!iframe) return; } } if (e.source === iframe.contentWindow) { // Assume that the player is ready if we receive a // message from the iframe clearInterval(queue.poller); queue.ready = true; messageEvent(0, runOnceReady); // .. and release the queue: while (tmp = queue.shift()) { callPlayer(frame_id, tmp[0], tmp[1]); } } }, false); } } else if (iframe && iframe.contentWindow) { // When a function is supplied, just call it (like "onYouTubePlayerReady") if (func.call) return func(); // Frame exists, send message iframe.contentWindow.postMessage(JSON.stringify({ "event": "command", "func": func, "args": args || [], "id": frame_id }), "*"); } /* IE8 does not support addEventListener... */ function messageEvent(add, listener) { var w3 = add ? window.addEventListener : window.removeEventListener; w3 ? w3('message', listener, !1) : (add ? window.attachEvent : window.detachEvent)('onmessage', listener); } } 

    Uso:

     callPlayer("whateverID", function() { // This function runs once the player is ready ("onYouTubePlayerReady") callPlayer("whateverID", "playVideo"); }); // When the player is not ready yet, the function will be queued. // When the iframe cannot be found, a message is logged in the console. callPlayer("whateverID", "playVideo"); 

    Possibili domande (e risposte):

    D : Non funziona!
    A : “Non funziona” non è una descrizione chiara. Ricevi messaggi di errore? Si prega di mostrare il codice pertinente.

    D : Ho incorporato un video di YouTube usando ma la funzione non esegue alcuna funzione!
    A : Devi aggiungere ?enablejsapi=1 alla fine del tuo URL: /embed/vid_id?enablejsapi=1 .

    D : Ricevo un messaggio di errore “È stata specificata una stringa non valida o illegale”. Perché?
    A : L’API non funziona correttamente su un host locale ( file:// ). Ospita la tua pagina (di prova) online o usa JSFiddle . Esempi: vedere i collegamenti nella parte superiore di questa risposta.

    Q : Come lo sapevi?
    A : Ho trascorso un po ‘di tempo per interpretare manualmente la fonte dell’API. Ho concluso che dovevo usare il metodo postMessage . Per sapere quali argomenti passare, ho creato un’estensione di Chrome che intercetta i messaggi. Il codice sorgente per l’estensione può essere scaricato qui .

    D : Quali browser sono supportati?
    A : Ogni browser che supporta JSON e postMessage .

    • IE 8+
    • Firefox 3.6+ (in realtà 3.5, ma document.readyState stato implementato in 3.6)
    • Opera 10.50+
    • Safari 4+
    • Chrome 3+

    Risposta / implementazione correlate: dissolvenza in entrata in un video incorniciato utilizzando jQuery
    Supporto completo dell’API: ascolto dell’evento Youtube in jQuery
    API ufficiale: https://developers.google.com/youtube/iframe_api_reference

    Cronologia delle revisioni

    • 17 maggio 2012
      Implementato callPlayer('frame_id', function() { ... }) : callPlayer('frame_id', function() { ... }) .
      Le funzioni vengono automaticamente messe in coda quando il giocatore non è ancora pronto.
    • 24 luglio 2012
      Aggiornato e testato correttamente nei browser supportati (guarda avanti).
    • 10 ottobre 2013 Quando una funzione viene passata come argomento, callPlayer forza un controllo di prontezza. Questo è necessario, perché quando callPlayer viene chiamato subito dopo l’inserimento dell’iframe mentre il documento è pronto, non può sapere con certezza che l’iframe sia completamente pronto. In Internet Explorer e Firefox, questo scenario ha provocato un’invocazione troppo presto di postMessage , che è stata ignorata.
    • 12 dicembre 2013, consigliato di aggiungere &origin=* nell’URL.
    • 2 marzo 2014, ritirato il consiglio di rimuovere &origin=* all’URL.

    Sembra che YouTube abbia aggiornato la sua API JS in modo che sia disponibile per impostazione predefinita! Puoi utilizzare un ID iframe di YouTube esistente …

      

    … nel tuo JS …

     var player; function onYouTubeIframeAPIReady() { player = new YT.Player('player', { events: { 'onStateChange': onPlayerStateChange } }); } function onPlayerStateChange() { //... } 

    … e il costruttore utilizzerà il tuo iframe esistente invece di sostituirlo con uno nuovo. Questo significa anche che non devi specificare il videoId al costruttore.

    Vedi Caricamento di un video player

    Puoi farlo con molto meno codice:

     function callPlayer(func, args) { var i = 0, iframes = document.getElementsByTagName('iframe'), src = ''; for (i = 0; i < iframes.length; i += 1) { src = iframes[i].getAttribute('src'); if (src && src.indexOf('youtube.com/embed') !== -1) { iframes[i].contentWindow.postMessage(JSON.stringify({ 'event': 'command', 'func': func, 'args': args || [] }), '*'); } } } 

    Esempio di lavoro: http://jsfiddle.net/kmturley/g6P5H/296/

    La mia versione del codice di Kim T sopra la quale si combina con alcuni jQuery e consente il targeting di iframe specifici.

     $(function() { callPlayer($('#iframe')[0], 'unMute'); }); function callPlayer(iframe, func, args) { if ( iframe.src.indexOf('youtube.com/embed') !== -1) { iframe.contentWindow.postMessage( JSON.stringify({ 'event': 'command', 'func': func, 'args': args || [] } ), '*'); } }