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 } }); } 

该代码创建一个新的玩家对象,并将其分配给“玩家”,然后将其插入到#container div中。 然后我可以在“播放器”上操作,并在其上调用playVideo()pauseVideo()等。

但是我希望能够在已经在页面上的iframe播放器上进行操作。

我可以很容易地用旧的嵌入方法来做到这一点,例如:

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

但是这不适用于新的iframe。 我怎样才能分配页面上的iframe对象,然后使用它的API函数?

小提琴链接: 源代码 – 预览 – 小版本
更新:这个小函数将只执行一个方向的代码。 如果你想完全支持(例如事件监听器/获取器),请看jQuery中的Listening for Youtube Event

作为深入的代码分析的结果,我创建了一个函数: function callPlayer在任何带框的YouTube视频上请求函数调用。 请参阅YouTube Api参考以获取可能的函数调用的完整列表。 阅读源代码中的注释以获得解释。

2012年5月17日,为了照顾玩家的准备状态,代码大小加倍。 如果你需要一个不涉及玩家就绪状态的紧凑函数,请参阅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"); 

可能的问题(&答案):

:这是行不通的!
:“不起作用”不是一个明确的描述。 你有什么错误信息吗? 请显示相关的代码。

:我已经使用<iframe src="http://www.youtube.com/embed/As2rZGPGKDY" />嵌入了YouTube视频,但该功能不会执行任何功能!
:您必须在URL末尾添加?enablejsapi=1/embed/vid_id?enablejsapi=1

:我收到错误消息“指定了无效或非法的字符串”。 为什么?
:API在本地主机( file:// )上无法正常工作。 在线托管您的(测试)页面,或使用JSFiddle 。 示例:请参阅此答案顶部的链接。

:你怎么知道这个?
:我花了一些时间来手动解释API的来源。 我的结论是我必须使用postMessage方法。 要知道哪些参数通过,我创建了一个截取消息的Chrome扩展。 扩展的源代码可以在这里下载。

:哪些浏览器支持?
:支持JSON和postMessage每个浏览器。

  • IE 8+
  • Firefox 3.6+(实际上3.5,但document.readyState在3.6中实现)
  • 歌剧10.50 +
  • Safari 4+
  • Chrome 3+

相关的答案/实现: 使用jQuery淡入一个带框的视频
完整的API支持: 在jQuery中监听Youtube事件
官方API: https : //developers.google.com/youtube/iframe_api_reference

修订记录

  • 2012年5月17日
    实现callPlayer('frame_id', function() { ... })callPlayer('frame_id', function() { ... })
    当玩家尚未准备好时,功能会自动排队。
  • 2012年7月24日
    在支持的浏览器中更新并进行了测试(展望未来)。
  • 2013年10月10日当函数作为参数传递时, callPlayer强制检查准备情况。 这是必要的,因为当文档准备就绪时插入iframe之后调用callPlayer时,它无法确定iframe是否已经准备就绪。 在Internet Explorer和Firefox中,这种情况导致过早地调用postMessage ,这被忽略了。
  • 2013年12月12日,建议在URL中添加&origin=*
  • 2014年3月2日,收回的建议删除&origin=*到URL。

看起来YouTube已经更新了他们的JS API,所以这个默认是可用的! 您可以使用现有的YouTube iframe的ID …

 <iframe id="player" src="http://www.youtube.com/embed/M7lc1UVf-VE?enablejsapi=1&origin=http://example.com" frameborder="0"></iframe> 

…在你的JS …

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

…和构造函数将使用您现有的iframe,而不是用新的替换它。 这也意味着你不必指定videoId给构造函数。

请参阅加载视频播放器

你可以用少得多的代码来做到这一点:

 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 || [] }), '*'); } } } 

工作示例: http : //jsfiddle.net/kmturley/g6P5H/296/

我自己的版本的金T的代码上面,它结合了一些jQuery,并允许针对特定的内联框架。

 $(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 || [] } ), '*'); } }