在JavaScript或jQuery中监听Youtube事件

23

我有一个滑块,其中包含4个通过iframe嵌入代码嵌入的youtube视频。

http://www.youtube.com/embed/'.$i.'?enablejsapi=1

我试图使任何一个视频的onStateChange事件调用一个名为stopCycle()的函数,当视频开始播放时停止滑块。iframes没有ID。我不确定如何正确捕获此事件,并可以使用任何关于我错过什么的建议。

<script charset="utf-8" type="text/javascript" src="http://www.youtube.com/player_api"></script>

var playerObj = document.getElementById("tab2"); // the container for 1 of the 4 iframes

playerObj.addEventListener("onStateChange", "stopCycle");

function stopCycle(event) {
    alert('Stopped!');
}
4个回答

44

YouTube Frame API支持现有的frame。为了提高使用效率,我创建了一些辅助函数。请查看下面的代码和注释以及演示:http://jsfiddle.net/YzvXa/197

要将函数绑定到现有的frame,您需要将ID引用传递给frame。在您的情况下,该frame包含在具有id="tab2"的容器中。我已经定义了一个自定义函数,以便更轻松地实现:

function getFrameID(id){
    var elem = document.getElementById(id);
    if (elem) {
        if(/^iframe$/i.test(elem.tagName)) return id; //Frame, OK
        // else: Look for frame
        var elems = elem.getElementsByTagName("iframe");
        if (!elems.length) return null; //No iframe found, FAILURE
        for (var i=0; i<elems.length; i++) {
           if (/^https?:\/\/(?:www\.)?youtube(?:-nocookie)?\.com(\/|$)/i.test(elems[i].src)) break;
        }
        elem = elems[i]; //The only, or the best iFrame
        if (elem.id) return elem.id; //Existing ID, return it
        // else: Create a new ID
        do { //Keep postfixing `-frame` until the ID is unique
            id += "-frame";
        } while (document.getElementById(id));
        elem.id = id;
        return id;
    }
    // If no element, return null.
    return null;
}

// Define YT_ready function.
var YT_ready = (function() {
    var onReady_funcs = [], api_isReady = false;
    /* @param func function     Function to execute on ready
     * @param func Boolean      If true, all qeued functions are executed
     * @param b_before Boolean  If true, the func will added to the first
                                 position in the queue*/
    return function(func, b_before) {
        if (func === true) {
            api_isReady = true;
            while (onReady_funcs.length) {
                // Removes the first func from the array, and execute func
                onReady_funcs.shift()();
            }
        } else if (typeof func == "function") {
            if (api_isReady) func();
            else onReady_funcs[b_before?"unshift":"push"](func); 
        }
    }
})();
// This function will be called when the API is fully loaded
function onYouTubePlayerAPIReady() {YT_ready(true)}

// Load YouTube Frame API
(function() { // Closure, to not leak to the scope
  var s = document.createElement("script");
  s.src = (location.protocol == 'https:' ? 'https' : 'http') + "://www.youtube.com/player_api";
  var before = document.getElementsByTagName("script")[0];
  before.parentNode.insertBefore(s, before);
})();

// 之前定义了核心函数。请预先查看实现:

var player; //Define a player object, to enable later function calls, without
            // having to create a new class instance again.

// Add function to execute when the API is ready
YT_ready(function(){
    var frameID = getFrameID("tabs2");
    if (frameID) { //If the frame exists
        player = new YT.Player(frameID, {
            events: {
                "onStateChange": stopCycle
            }
        });
    }
});

// Example: function stopCycle, bound to onStateChange
function stopCycle(event) {
    alert("onStateChange has fired!\nNew state:" + event.data);
}

如果您想在稍后的时间调用其他函数,例如静音视频,请使用:

player.mute();
  • 如果你只需要调用简单的单向函数,那么使用这段代码并不必要。相反,使用在这个答案中定义的函数callPlayer
  • 如果你想要同时为多个框架实现此功能,请查看这个答案。还包括对getFrameIDYT_ready的详细解释。

1
@RobW,我在我的原始问题中提供了一个示例,这样您就可以看到我正在尝试做什么 - 基本上是在单击自定义缩略图时启动视频。这是我的问题链接,供未来访问者使用 - https://dev59.com/pGox5IYBdhLWcg3wznk0 - SparrwHawk
1
@absynthemindedwebsmith 使用一个 if 语句,例如:if (event.data == -1) return; - Rob W
onstateChanged事件不总是触发,因为状态可能已经被预先设置了。因此,在使用new YT.Player调用播放器后,请使用player.getPlayerState()检查状态。如果它是5== YT.PlayerState.CUED),则调用您想要首先调用的函数。 - yunzen
我想知道在访问播放器的本机HTMLMediaElement接口时是否有任何方法可以避免框架边界的问题?例如,如果我想从iframe外部获取video元素的属性,如webkitVideoBytesDecoded,有什么办法吗? - slhck
@slhck,由于同源策略,这是不可能的。如果你真的想要那些信息,你可以尝试在JS中重新创建播放器的功能。但这需要相当多的工作,所以…… - Rob W
显示剩余16条评论

1
自从昨天起,这段代码就不能正常工作了。onStateChange事件没有被触发。 Jeffrey发布了一个快速修复方案,但我无法更新上面的答案。
关于此问题的更多信息https://code.google.com/p/gdata-issues/issues/detail?id=4706 使用该修复方案后,它可以正常工作了 :-)
添加以下函数:
function onReady() {
    player.addEventListener('onStateChange', function(e) {
        console.log('State is:', e.data);
    });
}

在“onStateChange”之前添加“stopCycle”,并添加“onReady”:“onReady”。

1
你可以使用tubeplayer插件,它带有许多事件可供监听。

我的iframes无法动态生成,它们是通过php创建的。 - Dave Kiss

0

我在我的聊天功能中添加了一个功能,使用户可以从YouTube发布视频。

视频的URL作为现有iframe的源附加。

我注意到的是,尽管添加了“?enablejsapi=1”,但该脚本仅适用于页面加载时存在的iframe。

当希望在为iframe设置新源后绑定此脚本时,应该如何操作?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接