YouTube iframe API:如何控制HTML中已经存在的iframe播放器? [英] YouTube iframe API: how do I control an iframe player that's already in the HTML?

查看:105
本文介绍了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?

推荐答案

小提琴链接:源代码-预览-在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

经过深入的代码分析,我创建了一个函数:function 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      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");

可能的问题(和答案):

:这不起作用!
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.

Q :playVideo无法播放视频.
A :播放需要用户交互,并且iframe上必须存在allow="autoplay".请参见 https://developers.google.com/web/updates/2017/09/autoplay-policy-changes https://developer.mozilla.org/en-US/docs/Web/Media/Autoplay_guide

Q: playVideo does not play the video.
A: Playback requires user interaction, and the presence of allow="autoplay" on the iframe. See https://developers.google.com/web/updates/2017/09/autoplay-policy-changes and https://developer.mozilla.org/en-US/docs/Web/Media/Autoplay_guide

:我已经使用<iframe src="http://www.youtube.com/embed/As2rZGPGKDY" />嵌入了YouTube视频,但是该功能无法执行任何功能!
A :您必须在URL的末尾添加?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.

Q :我收到错误消息指定了无效或非法字符串".为什么?
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

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() { ... }).
    播放器尚未准备就绪时,功能会自动排队.
  • 2012年7月24日
    在支持的浏览器中进行了更新并成功进行了测试(展望未来).
  • 2013年10月10日 当函数作为参数传递时,callPlayer强制检查准备情况.这是必需的,因为在文档准备就绪后插入iframe之后立即调用callPlayer时,它无法确定iframe是否已完全准备就绪.在Internet Explorer和Firefox中,这种情况导致postMessage的调用太早,被忽略了.
  • 2013年12月12日,建议在URL中添加&origin=*.
  • 2014年3月2日,撤消了将&origin=*删除到网址的建议.
  • 2019年4月9日,修复了在页面准备就绪之前加载YouTube时导致无限递归的错误.添加有关自动播放的注释.
  • 17 may 2012
    Implemented onYouTubePlayerReady: 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 when callPlayer 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 of postMessage, which was ignored.
  • 12 Dec 2013, recommended to add &origin=* in the URL.
  • 2 Mar 2014, retracted recommendation to remove &origin=* to the URL.
  • 9 april 2019, fix bug that resulted in infinite recursion when YouTube loads before the page was ready. Add note about autoplay.

这篇关于YouTube iframe API:如何控制HTML中已经存在的iframe播放器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆