YouTube iframe API:如何控制HTML中已经存在的iframe播放器?

2020/11/10 11:22 · javascript ·  · 0评论

我希望能够控制基于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中。然后,我可以在“播放器”和呼叫操作playVideo()pauseVideo()就可以了,等等。

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

我可以使用旧的embed方法非常轻松地执行此操作,例如:

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

但这不适用于新的iframe。如何在页面上分配iframe对象,然后在其上使用API​​函数?

小提琴链接:源代码-预览-小版本

更新:此小功能将仅在单个方向上执行代码。
如果你想完全支持(如事件监听器/吸气),看看
侦听YouTube事件中的jQuery

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

可能的问题(和答案):

:这不起作用!
:“无效”不是一个清晰的描述。您收到任何错误消息吗?请显示相关代码。

playVideo不播放视频。
:播放需要用户交互以及allow="autoplay"iframe上的存在请参阅https://developers.google.com/web/updates/2017/09/autoplay-policy-changeshttps://developer.mozilla.org/zh-CN/docs/Web/Media/Autoplay_guide

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

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

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

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

  • IE 8+
  • Firefox 3.6+(实际上是3.5,但document.readyState已在3.6中实现)
  • Opera 10.50+
  • Safari 4+
  • 铬3+

相关答案/实现:使用jQuery

Full API支持
淡入框架视频
在jQuery

官方API中
监听YouTube事件https
//developers.google.com/youtube/iframe_api_reference

修订记录

  • 于2012年5月17日

    实施
    onYouTubePlayerReadycallPlayer('frame_id', function() { ... })

    播放器尚未准备就绪时,功能会自动排队。
  • 2012年7月24日,

    更新并在受支持的浏览器中进行了成功测试(请注意)。
  • 2013年10月10日当函数作为参数传递时,callPlayer强制检查准备情况。这是必需的,因为在callPlayer文档准备就绪时,在插入iframe之后立即调用,无法确定iframe是否已完全准备就绪。在Internet Explorer和Firefox中,这种情况导致的调用时间太早postMessage,被忽略了。
  • 2013年12月12日,建议添加&origin=*URL。
  • 2014年3月2日,撤消了删除&origin=*该URL的建议
  • 2019年4月9日,修复了在页面准备就绪之前加载YouTube时导致无限递归的错误。添加有关自动播放的注释。

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,而不是将其替换为新的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/

我自己的Kim T上面的代码版本结合了jQuery,并允许定位特定的iframe。

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

谢谢Rob W的回答。

我在Cordova应用程序中一直在使用它,以避免必须加载API,因此我可以轻松控制动态加载的iframe。

我一直希望能够从iframe中提取信息,例如状态(getPlayerState)和时间(getCurrentTime)。

Rob W帮助突出显示了如何使用postMessage进行API的工作,但是当然,这仅从一个方向将信息从我们的网页发送到iframe。访问吸气剂要求我们监听从iframe发回给我们的消息。

我花了一些时间弄清楚如何调整Rob W的答案来激活和收听iframe返回的消息。我基本上在YouTube iframe中搜索了源代码,直到找到负责发送和接收消息的代码。

关键是将“事件”更改为“监听”,这基本上可以访问所有旨在返回值的方法。

以下是我的解决方案,请注意,只有在要求使用吸气剂时,我才切换到“监听”,您可以调整条件以包括其他方法。

Note further that you can view all messages sent from the iframe by adding a console.log(e) to the window.onmessage. You will notice that once listening is activated you will receive constant updates which include the current time of the video. Calling getters such as getPlayerState will activate these constant updates but will only send a message involving the video state when the state has changed.

function callPlayer(iframe, func, args) {
    iframe=document.getElementById(iframe);
    var event = "command";
    if(func.indexOf('get')>-1){
        event = "listening";
    }

    if ( iframe&&iframe.src.indexOf('youtube.com/embed') !== -1) {
      iframe.contentWindow.postMessage( JSON.stringify({
          'event': event,
          'func': func,
          'args': args || []
      }), '*');
    }
}
window.onmessage = function(e){
    var data = JSON.parse(e.data);
    data = data.info;
    if(data.currentTime){
        console.log("The current time is "+data.currentTime);
    }
    if(data.playerState){
        console.log("The player state is "+data.playerState);
    }
}
本文地址:http://javascript.askforanswer.com/youtube-iframe-apiruhekongzhihtmlzhongyijingcunzaideiframebofangqi.html
文章标签: ,   ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!