YouTube iframe API:如何控制已经在HTML中的iframe播放器?
我希望能够控制基于iframe的YouTube播放器。这些播放器已经在HTML中,但我想通过JavaScript API控制它们。
I want to be able to control iframe based YouTube players. This players will be already in the HTML, but I want to control them via the JavaScript API.
我一直在阅读 iframe API的文档,说明如何使用API向网页添加新视频,然后使用YouTube播放器功能控制它:
I've been reading the documentation for the iframe API which explain how to add a new video to the page with the API, and then control it with the YouTube player functions:
var player;
function onYouTubePlayerAPIReady() {
player = new YT.Player('container', {
height: '390',
width: '640',
videoId: 'u1zgFlCw8Aw',
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
该代码创建一个新的玩家对象并将其分配给玩家,然后将其插入#container div中。然后我可以操作'播放器'并在其上调用 playVideo()
, pauseVideo()
等。
That code creates a new player object and assigns it to 'player', then inserts it inside the #container div. Then I can operate on 'player' and call playVideo()
, pauseVideo()
, etc. on it.
但我希望能够对页面上已经存在的iframe播放器进行操作。
我可以使用旧的embed方法很容易地做到这一点,例如:
I could do this very easily with the old embed method, with something like:
player = getElementById('whateverID');
player.playVideo();
但这不适用于新的iframe。如何在页面上分配iframe对象,然后在其上使用API函数?
But this doesn't work with the new iframes. How can I assign a iframe object already on the page and then use the API functions on it?
小提琴链接:源代码 - 预览 - 小版本
更新:这个小功能只会在单个方向上执行代码。如果您需要完全支持(例如事件监听器/ getter),请查看 at 在jQuery中收听Youtube事件
Fiddle Links: Source code - Preview - Small version
Update: This small function will only execute code in a single direction. If you want full support (eg event listeners / getters), have a look at Listening for Youtube Event in jQuery
由于深度代码分析,我创建了一个功能:函数callPlayer
请求对任何带框的YouTube视频进行函数调用。请参阅 YouTube Api参考以获取可能的函数调用的完整列表。阅读源代码中的注释以获得解释。
As a result of a deep code analysis, I've created a function: function callPlayer
requests a function call on any framed YouTube video. See the YouTube Api reference to get a full list of possible function calls. Read the comments at the source code for an explanation.
2012年5月17日,代码大小加倍,以便处理播放器的就绪状态。如果您需要一个不处理播放器就绪状态的紧凑功能,请参阅 http://jsfiddle.net/8R5y6/ 。
On 17 may 2012, the code size was doubled in order to take care of the player's ready state. If you need a compact function which does not deal with the player's ready state, see http://jsfiddle.net/8R5y6/.
/**
* @author Rob W <gwnRob@gmail.com>
* @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);
}
}
用法:
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 :不起作用不是一个明确的描述。你收到任何错误信息吗?请显示相关代码。
Possible questions (& answers):
Q: It doesn't work!
A: "Doesn't work" is not a clear description. Do you get any error messages? Please show the relevant code.
问:我使用< iframe src =http嵌入了YouTube视频://www.youtube.com/embed/As2rZGPGKDY/>
但该功能不执行任何功能!
A :你必须在网址末尾添加?enablejsapi = 1
: / embed / vid_id?enablejsapi = 1
。
Q: I have embedded a YouTube video using <iframe src="http://www.youtube.com/embed/As2rZGPGKDY" />
but the function doesn't execute any function!
A: You have to add ?enablejsapi=1
at the end of your URL: /embed/vid_id?enablejsapi=1
.
问:我收到错误消息指定了无效或非法的字符串。为什么?
A :API在本地主机上无法正常运行( file://
)。在线托管您的(测试)页面,或使用 JSFiddle 。示例:请参阅此答案顶部的链接。
Q: I get error message "An invalid or illegal string was specified". Why?
A: The API doesn't function properly at a local host (file://
). Host your (test) page online, or use JSFiddle. Examples: See the links at the top of this answer.
问:您是怎么知道的?
A :我花了一些时间来手动解释API的来源。我总结说我必须使用 postMessage
方法。要知道要传递哪些参数,我创建了一个拦截邮件的Chrome扩展程序。扩展程序的源代码可以这里下载。
Q: How did you know this?
A: I have spent some time to manually interpret the API's source. I concluded that I had to use the postMessage
method. To know which arguments to pass, I created a Chrome extension which intercepts messages. The source code for the extension can be downloaded here.
问:支持哪些浏览器?
A :支持 JSON 和 的postMessage
。
Q: What browsers are supported?
A: Every browser which supports JSON and postMessage
.
- IE 8 +
- Firefox 3.6+(实际上是3.5,但
document.readyState
在3.6)中实现。 - Opera 10.50 +
- Safari 4 +
- Chrome 3 +
- IE 8+
- Firefox 3.6+ (actually 3.5, but
document.readyState
was implemented in 3.6) - Opera 10.50+
- Safari 4+
- Chrome 3+
相关答案/实施:使用jQuery淡化框架视频
完整的API支持:在jQuery中监听Youtube事件
官方API: https://developers.google.com/youtube/iframe_api_reference
Related answer / implementation: Fade-in a framed video using jQuery
Full API support: Listening for Youtube Event in jQuery
Official API: https://developers.google.com/youtube/iframe_api_reference
- 2012年5月17日
已实施onYouTubePlayerReady
:callPlayer('frame_id',function(){...})
。
函数在t时自动排队他还没有准备好。 - 2012年7月24日
在支持的浏览器中更新并成功测试(展望未来)。 - 10十月2013
当函数作为参数传递时,callPlayer
强制检查就绪状态。这是必需的,因为在文档准备好后插入iframe后立即调用callPlayer
时,它无法确定iframe是否已完全就绪。在Internet Explorer和Firefox中,此方案导致过早调用postMessage
,这被忽略。 - 2013年12月12日,推荐在网址中添加
& origin = *
。 - 2014年3月2日,撤消建议删除
& ; origin = *
到URL。
- 17 may 2012
ImplementedonYouTubePlayerReady
:callPlayer('frame_id', function() { ... })
.
Functions are automatically queued when the player is not ready yet. - 24 july 2012
Updated and successully tested in the supported browsers (look ahead). - 10 october 2013
When a function is passed as an argument,
callPlayer
forces a check of readiness. This is needed, because whencallPlayer
is called right after the insertion of the iframe while the document is ready, it can't know for sure that the iframe is fully ready. In Internet Explorer and Firefox, this scenario resulted in a too early invocation ofpostMessage
, which was ignored. - 12 Dec 2013, recommended to add
&origin=*
in the URL. - 2 Mar 2014, retracted recommendation to remove
&origin=*
to the URL.