2009-04-24 16 views
20

Actualmente estoy tratando de usar la API de YouTube como parte de un complemento jQuery y me he encontrado con un pequeño problema.Uso de la API de JavaScript de Youtube con jQuery

La forma en que funciona la API YT es que carga el flash player y, cuando esté listo, lo devolverá a una función global llamada onYouTubePlayerReady(playerId). A continuación, puede usar esa identificación combinada con getElementById(playerId) para enviar llamadas de JavaScript al reproductor flash (es decir, player.playVideo();).

Puede adjuntar un detector de eventos al reproductor con player.addEventListener('onStateChange', 'playerState'); que enviará los cambios de estado a otra función global (en este caso playerState).

El problema es que no estoy seguro de cómo asociar un cambio de estado con un jugador específico. Mi plugin jQuery puede adjuntar alegremente más de un video a un selector y adjuntar eventos a cada uno, pero en el momento en que un estado realmente cambia pierdo la pista de qué jugador sucedió.

Espero que algún código de ejemplo pueda hacer cosas un poco más claras. El siguiente código debería funcionar bien en cualquier archivo html.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> 
<html> 
<head> 
    <meta http-equiv="Content-Type" content="application/text+html;utf-8"/> 

    <title>Sandbox</title> 

    <link type="text/css" href="http://jqueryui.com/latest/themes/base/ui.all.css" rel="stylesheet" /> 
<script type="text/javascript" src="http://www.google.com/jsapi"></script> 
<script type="text/javascript"> 
    google.load("jquery", "1.3.2"); 
    google.load("jqueryui", "1.7.0"); 
</script> 
<script type="text/javascript" src="http://swfobject.googlecode.com/svn/tags/rc3/swfobject/src/swfobject.js"></script> 
<script type="text/javascript"> 
(function($) { 
    $.fn.simplified = function() { 
     return this.each(function(i) { 
      var params = { allowScriptAccess: "always" }; 
      var atts = { id: "ytplayer"+i }; 
      $div = $('<div />').attr('id', "containerplayer"+i); 
      swfobject.embedSWF("http://www.youtube.com/v/QTQfGd3G6dg&enablejsapi=1&playerapiid=ytplayer"+i, 
           "containerplayer"+i, "425", "356", "8", null, null, params, atts); 
      $(this).append($div); 
     }); 
    } 
})(jQuery); 
function onYouTubePlayerReady(playerId) { 
    var player = $('#'+playerId)[0]; 
    player.addEventListener('onStateChange', 'playerState'); 
} 
function playerState(state) { 
    console.log(state); 
} 

$(document).ready(function() { 
    $('.secondary').simplified(); 
}); 
</script> 
</head> 
<body> 
    <div id="container"> 
     <div class="secondary"> 

     </div> 
     <div class="secondary"> 

     </div> 
     <div class="secondary"> 

     </div> 
     <div class="secondary"> 

     </div> 

    </div> 
</body> 

</html> 

Verá la console.log() outputtin información sobre los cambios de estado, pero, como he dicho, no sé cómo decirle qué jugador que está asociado.

¿Alguien tiene alguna idea sobre cómo evitar esto?

EDITAR: Lo siento, también debería mencionar que he tratado de envolver la llamada al evento en un cierre.

function onYouTubePlayerReady(playerId) { 
    var player = $('#'+playerId)[0]; 
    player.addEventListener('onStateChange', function(state) { 
    return playerState(state, playerId, player); }); 
} 

function playerState(state, playerId, player) { 
    console.log(state); 
    console.log(playerId); 
} 

En esta situación, playerState nunca se llama. Lo cual es extra frustrante.

Respuesta

23

Editar:

Al parecer llamando addEventListener en el objeto player hace que el script para ser utilizado como una cadena en una propiedad XML que se pasa al objeto flash - Esto descarta cierres y similares, así que es hora para una vieja escuela feo truco:

function onYouTubePlayerReady(playerId) { 
    var player = $('#'+playerId)[0]; 

    player.addEventListener('onStateChange', '(function(state) { return playerState(state, "' + playerId + '"); })'); 
} 

function playerState(state, playerId) { 
    console.log(state); 
    console.log(playerId); 
} 

Probado & trabajo!

+0

Eso fue lo primero que pensé también, pero en realidad no funciona aquí. playerState parece que nunca se llama. – Steerpike

+0

He probado su código como se publicó y enYouTubePlayerReady nunca se llama – Greg

+0

Los videos se reproducen bien a pesar de – Greg

5

Im usando jQuery SWFObject plugin, SWFobject

Es importante añadir & enablejsapi = 1 al final del vídeo

HTML:

<div id="embedSWF"></div> 

Jquery:

   $('#embedSWF').flash({ 
       swf: 'http://www.youtube.com/watch/v/siBoLc9vxac', 
       params: { allowScriptAccess: "always"}, 
       flashvars: {enablejsapi: '1', autoplay: '0', allowScriptAccess: "always", id: 'ytPlayer' }, 
       height: 450, width: 385 }); 

function onYouTubePlayerReady(playerId) { 
       $('#embedSWF').flash(function(){this.addEventListener("onStateChange", "onPlayerStateChange")}); 
      } 
function onPlayerStateChange(newState) { 
        alert(newState); 
       } 

enYouTubePlayerReady debe estar fuera de $ (documento).listo (función() para ser despedido

+0

¡Buena llamada al plugin! – grant

+1

"onYouTubePlayerReady debe estar fuera de $ (documento). Listo (función() para ser despedido" - me salvó la vida – Mustafa

+4

Una pequeña nota: el código de la función onYouTubePlayerReady() puede estar * dentro * del $ (documento) .ready , pero debe ser * scoped * a la ventana/objeto global fuera de jQuery, por lo que la función tendría que definirse como tal: window.onYouTubePlayerReady (playerId) {} ​​ – TimKlimowicz

1

Tuve el mismo problema e intenté con la respuesta aceptada. Esto no funcionó, la función playerState() nunca se llamó. Sin embargo, me puso en el camino correcto. lo que terminé haciendo fue la siguiente:.

// Within my mediaController "class" 
window["dynamicYouTubeEventHandler" + playerID] = function(state) { onYouTubePlayerStateChange(state, playerID); } 
    embedElement.addEventListener("onStateChange", "dynamicYouTubeEventHandler" + playerID); 
// End mediaController class 

// Global YouTube event handler 
function onYouTubePlayerStateChange(state, playerID) { 
    var mediaController = GetMediaControllerFromYouTubeEmbedID(playerID); 
    mediaController.OnYouTubePlayerStateChange(state); 
} 

es bastante desagradable, pero también lo es el estado actual de la API de JavaScript de YouTube


Aquí es algún otro código útil/desagradable si está utilizando cualquier tipo de patrones avanzados de prototipos. Esto básicamente le permite recuperar una "clase" en la postura del reproductor de YouTube ID:

// Within my mediaController "class" 
// The containerJQElement is the jQuery wrapped parent element of the player ID 
// Its ID is the same as the player ID minus "YouTubeEmbed". 
var _self = this; 
containerJQElement.data('mediaController', _self); 
// End mediaController class 

// Global YouTube specific functions 
function GetMediaControllerFromYouTubeEmbedID(embedID) {  
    var containerID = embedID.replace('YouTubeEmbed', ''); 
    var containerJQObject = $("#" + containerID); 
    return containerJQObject.data('mediaController');  
} 

function onYouTubePlayerReady(playerId) { 
    var mediaController = GetMediaControllerFromYouTubeEmbedID(playerId); 
    mediaController.OnYouTubeAPIReady(); 
} 
+0

Esto no estaba muy claro para mí. obtener una "clase" mediaController? – Volomike

+0

@Volomike es simplemente un objeto de JavaScript autodefinido que se utiliza para ayudar a controlar el elemento de YouTube. – JoshNaro

0

¿Qué tal algo así:

var closureFaker = function (func, scope) { 
    var functionName = 'closureFake_' + (((1+Math.random())*0x10000000)|0).toString(16); 
    window[functionName] = function() { 
     func.apply(scope || window, arguments); 
    }; 
    console.log('created function:', functionName, window[functionName]); 
    return functionName; 
}; 

ytplayer.addEventListener("onStateChange", closureFaker(function() { 
    //place your logic here 
    console.log('state change', arguments) 
})); 
Cuestiones relacionadas