Javascript 事件监听器退出(?)监听... Youtube API - 没有控制台错误

Posted

技术标签:

【中文标题】Javascript 事件监听器退出(?)监听... Youtube API - 没有控制台错误【英文标题】:Javascript Event Listener quits (?) from listening... Youtube API - No console error 【发布时间】:2016-10-15 20:43:27 【问题描述】:

编辑 - 2016-06-25(我删除了 6 月 16 日的更新,因为不再相关。我在下面留下了我的 OP...)

我今天又花了 4 个小时来解决这个问题。 这是现在的情况:

我的函数 WORKS 用于两个链接。 视频参数在数组中定义。 其他两个链接失效。

我收到了链接 #3 和 #4 的 Uncaught TypeError: thisPlayer.loadVideoById is not a function。 但相同的功能适用于链接 #1 和 #2。

似乎 youtube 对象仅针对两个第一个定义。为什么?

请仔细查看此实时链接上的控制台:https://www.bessetteweb.com/?p=youtube-video-test 我插入了很多 console.log 消息来说明清楚。

这是我的实际代码:

// Global variable for the player
var player = [];
var statePlaying=false;

playerArr = [
            linkID:"link0",
            divID:"player1",
            ytID:"5V_wKuw2mvI", // Heavy metal playlist
            start:20,
            end:30
            ,
            
            linkID:"link1",
            divID:"player2",
            ytID:"u9Dg-g7t2l4", // Disturbed
            start:10,
            end:20
            ,
            
            linkID:"link2",
            divID:"player3",
            ytID:"39b5v3-d6ZA", // Maiden
            start:30,
            end:40
            ,
            
            linkID:"link3",
            divID:"player4",
            ytID:"z8ZqFlw6hYg", // Slayer
            start:120,
            end:136
            ];

// This function gets called when API is ready to use
function onYouTubePlayerAPIReady() 

    // Binding events loop
    console.log("playerArr.length: "+playerArr.length);
    for(i=0;i<playerArr.length;i++)
        console.log("");
        console.log("onPlayerReady for loop ->i: "+i);

        var playButton = document.getElementById(playerArr[i].linkID);
        console.log("playButton.id: "+playButton.id);

        var thisArr = playerArr[i];
        console.log("playerArr[i] object (below): ");
        console.log(thisArr);

        playButton.addEventListener("click", function() 
            thisLinkID = $(this).attr("id").replace("link","");

            console.log("");
            console.log("------------------");
            console.log("Link #"+(parseInt(thisLinkID)+1)+" clicked.");
            console.log("------------------");

            var ytID = playerArr[thisLinkID].ytID;
            var start = playerArr[thisLinkID].start;
            var end = playerArr[thisLinkID].end;

            var thisPlayer = new YT.Player(playerArr[thisLinkID].divID);

            console.log("ytID: "+ytID);
            console.log("start: "+start);
            console.log("end: "+end);
            console.log("");

            console.log("Below are the google ads, blocked by AdBlocker.");

            $("#ytplayerModal").css("display":"block");
            $("#ytplayerModal").animate("opacity":"0.7",1000,function()

                console.log("");
                console.log("player show()");
                $(".ytplayer").show();

                console.log("Youtube player object:");
                console.log(thisPlayer);
                console.log("");
                console.log('loadVideoById() parameters --\> videoId:'+ytID+', startSeconds:'+start+', endSeconds:'+end);

                thisPlayer.loadVideoById('videoId':ytID, 'startSeconds':start, 'endSeconds':end);
                console.log("");
            );

            // Bugfix - Set Interval instead of listener
            setTimeout(function()
                var IntervalCounter=0;
                listenerInterval = setInterval( function() 

                    var state = thisPlayer.getPlayerState();    //player[thisLinkID].getPlayerState();
                    var stateMsg;

                    switch (state)
                        case -1: stateMsg="unstarted"; thisPlayer.playVideo(); console.log("player["+thisLinkID+"]"); break;
                        case  0: stateMsg="ended"; break;
                        case  1: stateMsg="playing"; break;
                        case  2: stateMsg="paused"; break;
                        case  3: stateMsg="buffering"; break;
                        case  5: stateMsg="video cued"; break;
                        default: stateMsg="Undefined player state...";
                    
                    console.log(state+" : "+stateMsg);

                    if(state==1)
                        statePlaying=true;
                    

                    // Closes the modal
                    if((statePlaying) && (state==0))
                    //if((statePlaying) && (stateObj.data==0))
                        setTimeout(function()
                            console.log("Closing Modal");
                            $(".ytplayer").css("display":"none");
                            $("#ytplayerModal").animate("opacity":"0",1000,function()
                                $("#ytplayerModal").css("display":"none");
                            );
                            statePlaying=false;
                        ,500);
                        clearInterval(listenerInterval);
                        console.log("Interval loop stopped on video end.")
                    

                    // Stop the interval at 1000... Endless instead!
                    IntervalCounter++;
                    if((IntervalCounter>999)&&(state!=1)&&(state!=2)&&(state!=0))
                        clearInterval(listenerInterval);
                        console.log("Interval loop willingly stopped. Endless otherwise.")
                    
                , 10);
            ,1100);    // Interval setTimeout
        );
    


// Inject YouTube API script
var tag = document.createElement('script');
tag.src = "//www.youtube.com/player_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

这是我的控制台日志的快照:

-----------------这是我的原始帖子 - 6 月 14 日:强>

我已经为此花费了 6 个小时。(加上 1 个编辑这个问题!) 我正在调试它的最后 4 行。

问题是没有控制台错误提示。概念: 我想将大量 Youtube 视频链接到文本链接。 用户想要的效果是能够在阅读文本时单击引文链接...以便能够确认引文。 视频不能完全播放。

视频应以特定时间码开始并以特定时间码结束。额外的复杂性:所有这些都希望以模态视图样式显示。

我的代码在 ONE 视频中运行得非常快。 See here

我的代码基于this tutorial 并很快成功。

然后,让这个工作...... 我需要构建数组来处理多个视频。 对于链接 ID、玩家 ID、开始/结束时间码...和听众!乐趣开始了!

就像说的那样,我大部分时间都在这上面度过。 我总是遇到控制台错误作为明确 (LOLL) 指南的错误。

我对我的工作感到满意...我认为这是朝着正确的方向发展。 这几乎可以工作...但这一次,没有错误! See here。 (检查控制台!)

什么!!!没有错误?!? 我的手臂现在被砍掉了。 事实上,第一个节目但视频没有开始......第二个看起来完全迷失在阴霾中。

在控制台日志消息中,我看到onStateChange 侦听器的第一次出现,即 -1(未启动)。但是之后 ???它死了! 啊! 我必须超越我的自尊心......并将其作为一个问题带到 StackOveflow 上。 ;)

我的完整代码(用于多个链接):这是一个通过 ajax 调用的页面...所以所有外部资源(如 jQuery)都已加载.

<style>
.ytplayer
    position:fixed;
    z-index:2;
    width:60%;
    height:40%;
    top:30%;
    left:20%;
    display:none;

#ytplayerModal
    display:none;
    background-color:#000;
    opacity:0;
    position:fixed;
    z-index:1;
    top:0;
    left:0;
    width:100%;
    height:100%;

.ytTriggerPlay
    text-decoration:underline;
    color:dodgerblue;
    cursor:pointer;

</style>



<h1>Youtube modal trigger link test</h1>
<br>
<br>
<div id="text">
    Lorem ipsum dolor sit amet, consectetur <a id="0" class="ytTriggerPlay">adipiscing elit</a>. Quisque feugiat lectus ut est vestibulum ornare. Vivamus felis nulla, facilisis id cursus non, pharetra non diam. Sed pellentesque turpis vel sem tincidunt consectetur. Aenean ut lorem erat. Donec ut tellus sed leo ultrices cursus. <a id="1" class="ytTriggerPlay">Cras varius libero</a> ut purus suscipit ultrices. Vivamus eget efficitur turpis. Aenean suscipit, dui nec luctus fringilla, neque tellus fringilla risus, et porta enim justo et turpis. Sed risus orci, vehicula sed eleifend eget, tincidunt ut turpis. Vestibulum in sapien non lacus tristique mattis id eget tortor.<br>
    <br>
    Proin est purus, maximus id nunc vel, consectetur tristique urna. Mauris cursus ipsum a varius luctus. Nunc interdum condimentum massa vitae rutrum. Morbi volutpat nec lorem eleifend malesuada. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Duis fringilla metus vel nunc elementum efficitur. Duis sed dolor diam. In eu ultrices libero, eget lobortis mi. Sed pretium orci non augue vehicula, eget placerat leo lacinia. Sed sed gravida dui. Lorem ipsum dolor sit amet, consectetur adipiscing elit. In bibendum, erat eget venenatis elementum, nulla enim posuere lacus, quis efficitur dolor ex quis ipsum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Phasellus volutpat finibus odio id venenatis. Fusce at leo libero. Cras eget velit sed justo egestas vehicula efficitur sit amet ex.<br>
</div>

<!--iframe id="ytplayer" type="text/html"   src="https://www.youtube.com/embed/5V_wKuw2mvI?end=60&start=20" frameborder="0" allowfullscreen-->

<div id="ytplayerModal"></div>
<div id="player1" class="ytplayer"></div>
<div id="player2" class="ytplayer"></div>

<script>
// https://developers.google.com/youtube/iframe_api_reference
// https://css-tricks.com/play-button-youtube-and-vimeo-api/

// Global variable for the player
var player = [];
var statePlaying=false;

playerArr = [
            linkID:"0",
            divID:"player1",
            ytID:"5V_wKuw2mvI", // Heavy metal playlist
            start:20,
            end:40,
            ,
            
            linkID:"1",
            divID:"player2",
            ytID:"39b5v3-d6ZA", // Maiden
            start:30,
            end:60,
            ];

// This function gets called when API is ready to use

function onYouTubePlayerAPIReady() 
    for(i=0;i<playerArr.length;i++)
        // Create the global player from the specific iframe (#video)
        thisPlayer = new YT.Player(playerArr[i].divID, 
            height: '352',
            width: '640',
            videoId: '5V_wKuw2mvI',
            startSeconds:20,
            endSeconds:40,
            events: 
                // Call this function when player is ready to use
                // 'onReady': onPlayerReady         // Commented out willingly.
            
        );
        player[i] = thisPlayer;

    
    onPlayerReady();


function onPlayerReady(event) 

    // Binding events loop
    console.log("playerArr.length: "+playerArr.length);
    for(i=0;i<playerArr.length;i++)
        console.log("");
        console.log("onPlayerReady for loop ->i: "+i);

        var playButton = document.getElementById(playerArr[i].linkID);
        console.log("playButton.id: "+playButton.id);

        var thisArr = playerArr[i];
        console.log("playerArr[i] object (below): ");
        console.log(thisArr);

        var thissPlayer = player[i];

        playButton.addEventListener("click", function() 
            thisLinkID = parseInt($(this).attr("id"));
            console.log("thisLinkID: "+thisLinkID);

            var ytID = playerArr[thisLinkID].ytID;
            var start = playerArr[thisLinkID].start;
            var end = playerArr[thisLinkID].end;

            console.log("ytID: "+ytID);
            console.log("start: "+start);
            console.log("end: "+end);
            console.log("thissPlayer object (below): ");
            console.log(thissPlayer);

            $("#ytplayerModal").css("display":"block");
            $("#ytplayerModal").animate("opacity":"0.7",1000,function(thissPlayer,ytID,start,end)
                $(".ytplayer").show();

                player[thisLinkID].loadVideoById(videoId:ytID, startSeconds:start, endSeconds:end);
                setTimeout(function()
                    player[thisLinkID].playVideo();
                ,500);
            );
        );



        thissPlayer.addEventListener("onStateChange", function(stateObj)
            console.log("Player State: "+stateObj.data);
            console.log("Again, thissPlayer object in the onStateChange listener (below).");
            console.log(thissPlayer);
            // State sequence : -1, 3, 1, 2, 0, which is: Unstarted, Buffering, Playing, Paused, Ended.

            if(stateObj.data==1)
                statePlaying=true;
            
            console.log("Player State bolean memory: "+statePlaying);

            // Closes the modal
            if((statePlaying) && (stateObj.data==0))
                setTimeout(function()
                    console.log("Closing Modal");
                    $(".ytplayer").css("display":"none");
                    $("#ytplayerModal").animate("opacity":"0",1000,function()
                        $("#ytplayerModal").css("display":"none");
                    );
                    statePlaying=false;
                ,500);
            
        );
    


// Inject YouTube API script
var tag = document.createElement('script');
tag.src = "//www.youtube.com/player_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
</script>

【问题讨论】:

【参考方案1】:

iFrame Player API 存在一个临时问题,您可以在此处阅读:https://code.google.com/p/gdata-issues/issues/detail?id=4706

作为临时修复,您只需在 onReady 事件中添加事件侦听器:

function onReady() 
player.addEventListener('onStateChange', function(e) 
console.log('State is:', e.data);
);

另外,正如有人在 Google 代码问题线程中提到的那样,您设置了一个间隔并轮询播放器的当前状态,而不是监听 onStateChange 事件。这是一个示例代码 sn-p 用于执行此操作:

setInterval( function() 
var state = player.getPlayerState();
if ( playerState !== state ) 
onPlayerStateChange( 
data: state
);

, 10);

【讨论】:

看起来是找到我的修复的正确线索。我必须先尝试才能接受。但是,因为它看起来很严肃,我赞成它。我有一个晚上的会议,30 分钟后开始……所以我明天会认真检查。谢谢! 我用这个间隔的想法尝试了一些东西......我现在得到了一些新的东西。但我还在树林里。现在我得到 playerState= 5 (video cued) 1 秒。然后 3(缓冲)fo 80 毫秒。在此之后,间隔无限计数,玩家状态卡在 -1(未开始)。在我的work in progress link 上查看控制台我将编辑问题以显示我修改后的代码。 这个答案很有帮助。但是我的问题没有解决。我刚刚更新了我的问题,显示了我现在的位置。我有两 (2) 个链接正在工作……这是一项改进。但只有两个。你能看看我的新代码吗?

以上是关于Javascript 事件监听器退出(?)监听... Youtube API - 没有控制台错误的主要内容,如果未能解决你的问题,请参考以下文章

小功能⭐️退出游戏 && 监听事件

小功能⭐️退出游戏 && 监听事件

在uniapp中 监听回车事件

android可以监听application退出吗

android可以监听application退出吗

监听浏览器关闭事件