現在、jQueryプラグインの一部としてYouTube APIを使用しようとしていますが、少し問題が発生しました。
YT apiが機能する方法は、フラッシュプレーヤーをロードし、準備ができたら、onYouTubePlayerReady(playerId)
と呼ばれるグローバル関数にコールバックを送信することです。そのIDをgetElementById(playerId)
と組み合わせて、javascript呼び出しをFlash Playerに送信します(つまり、player.playVideo();
)。
player.addEventListener('onStateChange', 'playerState');
を使用して、イベントリスナーをプレーヤーにアタッチできます。これにより、状態の変化が別のグローバル関数(この場合はplayerState
)に送信されます。
問題は、状態の変化を特定のプレーヤーに関連付ける方法がわからないことです。私のjQueryプラグインは、複数のビデオをセレクターに接続し、それぞれにイベントを接続できますが、状態が実際に変化した瞬間に、どのプレーヤーで発生したかがわかりません。
いくつかのサンプルコードが物事を少し明確にするかもしれないことを願っています。以下のコードは、どの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>
状態の変化に関するconsole.log()outputtin情報が表示されますが、前述したように、どのプレーヤーに関連付けられているかを確認する方法がわかりません。
誰かがこれを回避する方法について何か考えがありますか?
編集:申し訳ありませんが、イベント呼び出しをクロージャでラップしようとしたことにも言及する必要があります。
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);
}
この状況では、playerState
は呼び出されません。これは非常に苛立たしいことです。
編集:
どうやらaddEventListener
オブジェクトでplayer
を呼び出すと、スクリプトがフラッシュオブジェクトに渡されるXMLプロパティの文字列として使用されるようになります。これにより、クロージャなどが除外されるため、昔ながらの醜いハック:
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);
}
テスト済みで動作中!
Jquery SWFobjectプラグインを使用しているIm、 SWFobject
ビデオの最後に&enablejsapi = 1を追加することが重要です
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);
}
onYouTubePlayerReadyを起動するには、$(document).ready(function()の外部にある必要があります
私はこれと同じ問題を抱えていて、受け入れられた答えを試しました。これは私にはうまくいきませんでした。 playerState()関数が呼び出されることはありませんでした。しかし、それは私を正しい道に導いた。私がやったことはこれでした:
// 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);
}
かなり厄介ですが、YouTube JavaScriptAPIの現在の状態も同様です。
高度なプロトタイピングパターンを使用している場合は、他の便利で厄介なコードを次に示します。これにより、基本的に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();
}
これは、前の回答で述べたのと同様のアプローチを使用して個々のオブジェクトにイベントをディスパッチすることを含め、個々のプレーヤーをラップするクラスを作成することを通過する素晴らしい記事です。
http://blog.jcoglan.com/2008/05/22/dispatching-youtube-api-events-to-individual-javascript-objects/
そのようなものはどうですか:
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)
}));