Javascript 当使用会话变量控制嵌入的YouTube播放器时,我收到错误:uncaughttypeerror:cannotcallmethod';后消息';空值?

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

尝试使用会话控制后,YouTube嵌入式播放器停止响应,并返回错误:
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替换div
ytplayer
,但由于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>