[解決済み] YouTube iframe API: HTML 内に既にある iframe プレーヤーを制御するにはどうすればよいですか?
質問
iframeベースのYouTubeプレイヤーを制御できるようにしたいです。このプレーヤーはすでにHTML内にありますが、JavaScript APIを介して制御したいのです。
を読みました。 iframe API のドキュメント には、API を使用して新しい動画をページに追加し、YouTube プレーヤの機能でそれを制御する方法が説明されています。
var player;
function onYouTubePlayerAPIReady() {
player = new YT.Player('container', {
height: '390',
width: '640',
videoId: 'u1zgFlCw8Aw',
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
このコードでは、新しいプレイヤー オブジェクトを作成して「player」に割り当て、それを #container div の中に挿入しています。次に、「player」に対して操作を行い、次のコードを呼び出します。
playVideo()
,
pauseVideo()
などが載っています。
しかし、すでにページ上にあるiframeプレーヤーに対して操作できるようにしたい。
旧来の埋め込み方式で、こんな感じで簡単にできました。
player = getElementById('whateverID');
player.playVideo();
しかし、これは新しいiframeではうまくいきません。ページ上にすでにあるiframeオブジェクトを割り当て、その上でAPI関数を使用するにはどうしたらよいでしょうか?
解決方法は?
フィドルリンク
ソースコード
-
プレビュー
-
小型版
更新:この小さな関数は、一方向にしかコードを実行しません。もし完全なサポート(例えばイベントリスナーやゲッター)をお望みでしたら、こちらをご覧ください。
で
jQueryでYoutubeのイベントをリスニングする
深いコード解析の結果、ある関数を作りました。
function callPlayer
は、フレーム化された任意の YouTube 動画に対して関数呼び出しを要求します。をご覧ください。
YouTube Api リファレンス
をクリックすると、可能な関数呼び出しの完全なリストが表示されます。ソースコードのコメントを読むと、説明があります。
2012年5月17日、プレイヤーのレディ状態を考慮し、コードサイズを2倍にしました。プレイヤーの準備状態を処理しないコンパクトな関数が必要な場合は、以下を参照してください。 http://jsfiddle.net/8R5y6/ .
/**
* @author Rob W <[email protected]>
* @website https://stackoverflow.com/a/7513356/938089
* @version 20190409
* @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 / .ready=true = 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 ((!queue || !queue.ready) && (
!domReady ||
iframe && !iframe.contentWindow ||
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);
}
}
使用方法
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");
想定される質問(&回答)。
Q
: 効かない!?
A
: "動作しません"は、明確な説明ではありません。何かエラーメッセージが表示されますか?該当するコードを表示してください。
Q
:
playVideo
が再生されません。
A
: 再生にはユーザーのインタラクションが必要であり、その存在によって
allow="autoplay"
をiframe上に表示します。参照
https://developers.google.com/web/updates/2017/09/autoplay-policy-changes
と
https://developer.mozilla.org/en-US/docs/Web/Media/Autoplay_guide
Q
: YouTubeの動画を
<iframe src="http://www.youtube.com/embed/As2rZGPGKDY" />
が、何の関数も実行されない!?
A
: を追加する必要があります。
?enablejsapi=1
をURLの末尾に追加してください。
/embed/vid_id?enablejsapi=1
.
Q
: エラーメッセージ "無効または不正な文字列が指定されました" が表示されます。なぜですか?
A
: ローカルホストでAPIが正しく動作しない(
file://
). あなたの (テスト) ページをオンラインでホストするか、または
JSFiddle
. 例 この回答の上部にあるリンクを参照してください。
Q
: なぜそれを知っているのですか?
A
: API のソースを手動で解釈するのに時間を費やしました。その結果、私は
postMessage
というメソッドがあります。どの引数を渡せばいいのかを知るために、メッセージを傍受するChromeの拡張機能を作りました。この拡張機能のソースコードは、以下のサイトからダウンロードできます。
こちら
.
Q
: 対応ブラウザは?
A
: をサポートするすべてのブラウザは
JSON
と
postMessage
.
- IE 8 以上
-
Firefox 3.6+ (実際は3.5ですが
document.readyState
は3.6で実装されました) - オペラ10.50以上
- サファリ 4 以上
- Chrome 3 以上
関連する回答・実装
jQueryを使ったフレーム付き動画のフェードイン
APIをフルサポート。
jQueryでYoutubeイベントをリスニングする
公式APIです。
https://developers.google.com/youtube/iframe_api_reference
改訂履歴
-
2012年5月17日
実装onYouTubePlayerReady
:callPlayer('frame_id', function() { ... })
.
プレーヤーがまだ準備できていない場合、関数は自動的にキューに入れられます。 -
2012年7月24日
更新し、対応ブラウザでの動作確認に成功しました(先読み)。 -
2013年10月10日
引数に関数が渡された場合。
callPlayer
は、準備完了のチェックを強制的に行います。このチェックが必要なのはcallPlayer
が iframe の挿入直後に呼び出された場合、ドキュメントの準備ができていても、iframe の準備が完全に整っていることを確実に知ることができません。Internet Explorer と Firefox では、このシナリオにより、iframe の挿入後すぐにpostMessage
これは無視されます。 -
2013年12月12日、追加を推奨
&origin=*
を URL に追加してください。 -
2014年3月2日、削除勧告を撤回
&origin=*
をURLに追加しました。 - 2019年4月9日、ページの準備が整う前にYouTubeが読み込まれると無限再帰が発生するバグを修正しました。自動再生に関する注意事項を追加。
関連
-
親子コンポーネント通信を解決する3つのVueスロット
-
JavaScriptにおけるマクロタスクとミクロタスクの詳細
-
Vueはランニングライト形式のテキストを水平方向にスクロールする機能を実装している
-
Vueのイベント処理とイベントモディファイアの解説
-
Vueのフィルタの説明
-
[解決済み】Node.js getaddrinfo ENOTFOUND
-
[解決済み】"フォームが接続されていないため、フォームの送信がキャンセルされました "というエラーの取得について
-
[解決済み] Web API エラー - このリクエストはブロックされました; コンテンツは HTTPS で提供されなければなりません
-
[解決済み】<select>で現在選択されている<option>をJavaScriptで取得するにはどうすればよいですか?
-
[解決済み] YouTube APIからYouTubeビデオのサムネイルを取得する方法を教えてください。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
JSクロスドメインソリューション リアクト構成 リバースプロキシ
-
要素ツリー制御によるvueTreeテーブル
-
Vue+ElementUIによる大規模なフォームの処理例
-
[解決済み】最大呼び出しスタックサイズ超過エラー
-
[解決済み】React - uncaught TypeError: 未定義のプロパティ 'setState' を読み取れない
-
[解決済み] テスト
-
[解決済み】リソースの読み込みに失敗した:Bind関数でサーバーが500(Internal Server Error)のステータスで応答した【非公開
-
[解決済み】 `string.split is not a function` というエラーの原因は何ですか?
-
[解決済み] Youtube api - 動画を停止する
-
フロントエンド null のプロパティ 'disabled' を読み取れない 問題が解決された