Javascript 当使用会话变量控制嵌入的YouTube播放器时,我收到错误:uncaughttypeerror:cannotcallmethod';后消息';空值?
尝试使用会话控制后,YouTube嵌入式播放器停止响应,并返回错误:Javascript 当使用会话变量控制嵌入的YouTube播放器时,我收到错误:uncaughttypeerror:cannotcallmethod';后消息';空值?,javascript,debugging,meteor,Javascript,Debugging,Meteor,尝试使用会话控制后,YouTube嵌入式播放器停止响应,并返回错误:uncaughttypeerror:cannotcall方法'postMessage'为null。这种情况并非每次都会发生,但可以通过在链接中输入歌曲并单击播放按钮来复制 以下是临时放置在HTML文件中的YouTube API的设置: mixstape.html <script> // Called automatically when JavaScript client library is loaded. fun
uncaughttypeerror:cannotcall方法'postMessage'为null
。这种情况并非每次都会发生,但可以通过在链接中输入歌曲并单击播放按钮来复制
以下是临时放置在HTML文件中的YouTube API的设置:
mixstape.html
<script>
// Called automatically when JavaScript client library is loaded.
function onClientLoad() {
gapi.client.load('youtube', 'v3', onYouTubeApiLoad);
}
// Called automatically when YouTube API interface is loaded
function onYouTubeApiLoad() {
gapi.client.setApiKey('AIzaSyD1VcsNnysOY6_Za-8kE-BK6Zh8jQwvo4w');
}
</script>
<script src="https://apis.google.com/js/client.js?onload=onClientLoad"></script>
<script src= "https://www.youtube.com/iframe_api"></script>
<script>
// Load the IFrame Player API code asynchronously.
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/player_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
// Replace the 'ytplayer' element with an <iframe> and
// YouTube player after the API code downloads.
var player;
function onYouTubePlayerAPIReady() {
console.log("playerAPIready");
player = new YT.Player('ytplayer', {
height: '400',
width: '640',
videoId: 'M7lc1UVf-VE',
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
//console.log("loaded");
$("#player").hide();
}
function onPlayerReady(){
//console.log("ready");
}
function onPlayerStateChange(){
//console.log("changed");
}
function generatePlaylist(list){
console.log("list: ", list)
player.loadPlaylist(list);
}
</script>
```
下面是给定值的会话变量。这些文件恰恰包含了它们应该包含的内容。当用户单击“播放”按钮时,它们会更新
/*Update List on generate button*/
Template.list.updateList = function(){
var ret = [];
$( "#playlist .list_element" ).each(function() {
if($(this).is(':visible')){
ret.push( Links.findOne({_id:$(this).attr('id')}) );
}
});
var urls = [];
for (var i = 0; i < ret.length; i++){
urls[i] = ret[i].videoId;
}
Session.set("current_list",ret);
Session.set("current_urls",urls);
}
问题似乎在于,尽管您在添加iFrame之前等待加载YouTube API,但您并没有等待DOM完成渲染,因此在脚本标记中调用
new YT.Player
时,您试图用iFrame(ytplayer
)替换的元素实际上并不存在。在这些情况下,任何时候尝试在已初始化的播放器上播放、停止、更改视频或任何其他内容都会导致此错误,即使相关元素随后添加到DOM中。您可以在控制台中手动运行脚本标记中的代码,然后您会发现,在播放器重新初始化时,所有内容都会按照元素的方式工作
我建议将整个代码段移动到js文件中的Template.player.rendered
函数中。您需要检查播放机是否已经创建(如果没有创建,则只运行代码),但是将所有内容放在这里而不是脚本标记将保证元素存在以及API已经加载。不管怎样,我相信你能解决的
更新:
由于脚本标记中的大部分工作都是通过回调完成的,因此将其添加到js文件实际上要容易得多:
Template.player.created = function() {
var tag = document.createElement('script');
tag.src = "https://apis.google.com/js/client.js?onload=onClientLoad";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
};
并将这一行从html中删除:
<script src="https://apis.google.com/js/client.js?onload=onClientLoad"></script>
如果我上面说的不清楚,我道歉。在您的版本中,YouTube API试图用iFrame替换divytplayer
,但由于Javascript位于脚本标记中,它在Meteor完成所有模板的渲染之前运行,这意味着ytplayer
在DOM中尚不存在,因此不会被替换。因此,尽管存在player
,但您不能使用它,因为DOM中没有iFrame。通过进行上述更改,您将仅在首次加载包含ytplayer
的模板后加载YouTube API,从而确保成功替换
请注意,如果您有任何明显的延迟,YouTube API可能在DOM完全呈现之前不会启动回调,在这种情况下,整个过程都会工作,我假设它偶尔会这样做。您的第一个链接似乎是dead@jyarbro你确定吗?我只能点击它。尝试将其粘贴到您的浏览器中:尝试理解您的注释-以便加载API,而不必等待
新的YT.Player
在DOM上呈现,因此每当我调用停止播放操作时,我都会得到错误?您建议从哪里调用Template.player.rendered
函数?onPlayerReady
功能?在包含您的修复后,我仍然会收到相同的错误消息。在将标签粘贴到控制台后,您是否能够使其正常工作?我实际上使用您的修复程序获得了视频,非常感谢!但是,依赖于会话变量的导航列表随后停止工作。我把它移到了一个单独的模板中,现在一切都正常工作了。
Template.header.events({
'click #generate_button': function (evt, template){
//bad code below:
Template.list.updateList();
if (Template.list.my_playlist().fetch().length == 0){
alert('Your tape is empty!');
}
else{
generatePlaylist( Session.get("current_urls") );
$("#playlist").css('display','none');
$("#player").fadeIn(1000);
$(".absolute_center").hide();
/*Things to hide*/
$(".absolute_center2").fadeIn();
$("#query").hide();
$("#share").fadeOut(1000);
$("#playlist_container").fadeOut(1000);
$('body').animate({backgroundColor: 'rgb(53,53,53)'}, 'slow');
$('#title').animate({color: '#fff'}, 'slow');
}
},
'click #close_player': function (evt, template){
player.stopVideo();
$(".absolute_center2").hide();
$("#player").hide();
$("#playlist").css('display','block');
/*Things that must reappear*/
$("#query").show();
$("#share").fadeIn(1000);
$(".absolute_center").fadeIn(1000);
$("#playlist_container").fadeIn(1000);
$('body').animate({backgroundColor: '#fff'}, 'slow');
$('#title').animate({color: '#000'}, 'slow');
}
});
Template.player.created = function() {
var tag = document.createElement('script');
tag.src = "https://apis.google.com/js/client.js?onload=onClientLoad";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
};
<script src="https://apis.google.com/js/client.js?onload=onClientLoad"></script>