YouTube API - iframe onStateChange 事件

Posted

技术标签:

【中文标题】YouTube API - iframe onStateChange 事件【英文标题】:YouTube API - iframe onStateChange events 【发布时间】:2014-08-28 13:52:10 【问题描述】:

我正在使用 iframe YouTube API,我想跟踪事件,例如,当用户开始和停止视频时,将数据发送到谷歌分析。

<iframe src="https://www.youtube.com/embed/DjB1OvEYMhY"></iframe>

我查看了https://developers.google.com/youtube/iframe_api_reference?csw=1 并没有找到如何做到这一点的示例。该示例创建 iframe 并定义了 onReady 和 onStateChange。如果页面上只有 iframe,我该怎么做?

【问题讨论】:

您应该能够按照function getPlayerState() if (ytplayer) return ytplayer. getPlayerState(); 的方式放入一个事件处理程序 - 希望有人可以演示它是如何产生结果的。恐怕真的帮不上忙。 【参考方案1】:

此示例使用 onPlayerStateChange 及其不同的 states 监听用户所做的每个播放/暂停操作,并打印(记录)它们。

但是,您需要创建自己的 record 函数才能对这些数据执行任何操作。

您还需要 iframe 上的 ID(在本例中为 #player)并在其 URL 的末尾添加 ?enablejsapi=1。当然,请确保包含Youtube iframe API。

注意

在您的代码之后声明 API 很重要,因为它会在准备好时调用 onYouTubeIframeAPIReady

<!DOCTYPE html>
<html>
<body>
    <iframe id="player" src="https://www.youtube.com/embed/DjB1OvEYMhY?enablejsapi=1"></iframe>
    <h5>Record of user actions:</h5>
    <script>
      var player;
      function onYouTubeIframeAPIReady() 
        player = new YT.Player( 'player', 
          events:  'onStateChange': onPlayerStateChange 
        );
      
      function onPlayerStateChange(event) 
        switch(event.data) 
          case 0:
            record('video ended');
            break;
          case 1:
            record('video playing from '+player.getCurrentTime());
            break;
          case 2:
            record('video paused at '+player.getCurrentTime());
        
      
      function record(str)
        var p = document.createElement("p");
        p.appendChild(document.createTextNode(str));
        document.body.appendChild(p);
      
    </script>
    <script src="https://www.youtube.com/iframe_api"></script>
</body>
</html>

JS Fiddle Demo

【讨论】:

【参考方案2】:

这是一个不使用 Youtubes iframe API 脚本的版本。唯一的缺点是 iframe API 可能会改变。

<iframe id="player" src="https://www.youtube.com/embed/dQw4w9WgXcQ?enablejsapi=1"></iframe>
var addYoutubeEventListener = (function() 

    var callbacks = [];
    var iframeId = 0;

    return function (iframe, callback) 

        // init message listener that will receive messages from youtube iframes
        if(iframeId === 0) 
            window.addEventListener("message", function (e) 

                if(e.origin !== "https://www.youtube.com" || e.data === undefined) return;
                try 
                    var data = JSON.parse(e.data);
                    if(data.event !== 'onStateChange') return;

                    var callback = callbacks[data.id];
                    callback(data);
                
                catch(e) 
            );
        

        // store callback
        iframeId++;
        callbacks[iframeId] = callback;
        var currentFrameId = iframeId;

        // sendMessage to frame to start receiving messages
        iframe.addEventListener("load", function () 
            var message = JSON.stringify(
                event: 'listening',
                id: currentFrameId,
                channel: 'widget'
            );
            iframe.contentWindow.postMessage(message, 'https://www.youtube.com');

            message = JSON.stringify(
                event: "command",
                func: "addEventListener",
                args: ["onStateChange"],
                id: currentFrameId,
                channel: "widget"
            );
            iframe.contentWindow.postMessage(message, 'https://www.youtube.com');
        );
    
)();
addYoutubeEventListener(document.getElementById("player"), function(e) 

    switch(e.info) 
        case 1:
            // playing
            break;
        case 0:
            // ended
            break;
    
);

【讨论】:

【参考方案3】:

有时事件加载不足以确保 iframe 内的文档准备就绪。如果 iframe 位于不同的域中,则无法订阅以查看它何时准备就绪。

一种可能的解决方法是记录从 iframe 接收到事件的时间,如果在订阅后未收到任何事件,请重试:

var addYoutubeEventListener = (function() 

   var callbacks = [];
   var iframeId = 0;
   var subscribed = [];

   return function (iframe, callback) 
       // init message listener that will receive messages from youtube iframes
       if(iframeId === 0) 
           window.addEventListener("message", function (e) 
               if(e.origin !== "https://www.youtube.com" || e.data === undefined) return;
               try 
                   var data = JSON.parse(e.data);
                   subscribed[data.id] = true;
                   if(data.event !== 'onStateChange') return;

                   var callback = callbacks[data.id];
                   callback(data);
               
               catch(e) 
           , true);
       

       // store callback
       iframeId++;
       callbacks[iframeId] = callback;
       subscribed[iframeId] = false;
       var currentFrameId = iframeId;

       //console.log("adding event listener to iframe id " + iframeId);

       // sendMessage to frame to start receiving messages
       iframe.addEventListener("load", function () 
           var tries = 0;
           var checkSubscribed = function()
           
               if (subscribed[currentFrameId]) 
                   //console.log("subscribed succesfully " + currentFrameId)
               
               else
               
                   tries++;
                   //console.log("Try again " + currentFrameId + " (" + tries + ")");
                   if (tries < 100) 
                       doSubscribe();
                   
                   else
                   
                       console.log("Unable to subscribe" + currentFrameId );
                   
               
           
           var doSubscribe = function()
           
               var message = JSON.stringify(
                    event: 'listening',
                    id: currentFrameId,
                    channel: 'widget'
                );
                iframe.contentWindow.postMessage(message, 'https://www.youtube.com');

                message = JSON.stringify(
                    event: "command",
                    func: "addEventListener",
                    args: ["onStateChange"],
                    id: currentFrameId,
                    channel: "widget"
                );
                iframe.contentWindow.postMessage(message, 'https://www.youtube.com');
                setTimeout(checkSubscribed, 100);
            ;
            doSubscribe();
       , true);
   
)();

【讨论】:

以上是关于YouTube API - iframe onStateChange 事件的主要内容,如果未能解决你的问题,请参考以下文章

动态创建的 iFrame 上的 YouTube iFrame API

如何启动和停止使用youtube iframe API创建的YouTube视频?

无法通过 api 调用 pauseVideo 访问 youtube 嵌入式 iframe

YouTube API - iframe onStateChange 事件

如何在现有iframe上使用YouTube API?

需要使用 iFrame API 隐藏 YouTube 品牌