YT.Player 没有 return 带有 playVideo() 的实例

YT.Player doesn't return an instance with playVideo()

当我创建 YT.Player(HTMLIFrameElement, { options }) 的实例时,我得到一个对象,该对象具有:

但不是 playVideopauseVideo 等,如 documentation 中所述。

我在这里有一个演示:http://siesta-annotations.surge.sh/Siesta_webviewer_test/?page=3

我正在通过 trait.playable.youtube.js 中的 DOM 创建 iframe,并将 iframe 添加到 documentFragment,最终将添加到 div:

const element = document.createElement('iframe')
element.src = `https://www.youtube.com/embed/${id}?rel=0;&autoplay=${this.options.autostart ? 1 : 0};&enablejsapi=1;&origin=${location.hostname};`
element.style = this.inlineStyle

然后我创建了一个实例 YT.Player:

// nasty initialization because we're outside webpack and this is a demo
if (global.YT.loaded) {
  this.player = new global.YT.Player(element, {
    events: {
      'onStateChange': this.stateHandler,
      'onReady': onPlayerReady
    }
  })
} else {
  const oldHandler = global.onYouTubeIframeAPIReady
  global.onYouTubeIframeAPIReady = () => {
    if (oldHandler) oldHandler()

    this.player = new global.YT.Player(element, {
      events: {
        'onStateChange': this.stateHandler,
        'onReady': onPlayerReady
      }
    })
  }
}

YT.Player 的实例看起来像这样:

看起来缩小过程出错了。我做错了什么 - 我应该如何为我的用例初始化 YT.Player?

奇怪的是,在构造函数播放器选项对象中调用 'onReady' 之前,您无法访问 YTPlayer API。 https://developers.google.com/youtube/iframe_api_reference#Loading_a_Video_Player

function onYouTubeIframeAPIReady() {
  new YT.Player('player', {
    height: '390',
    width: '640',
    videoId: 'M7lc1UVf-VE',
    events: {
      'onReady': function (event) {
        onPlayerReady(event.target)
      },
      'onStateChange': onPlayerStateChange
    }
  });
}

function onPlayerReady(player) {
  player.playVideo();
}

这当然只适用于一个播放器,因此如果您想处理多个播放器,则需要推出自己的 YouTube 播放器管理器。 (我知道 API 疯了)

如果您的 iframe 包含 YouTube 视频(未测试),可以采用以下快速解决方案:

const YTManager = {
  videos: [],
  youtubeApiReady = false,
  initialize () {
    const matchId = /[^/]+$/

    this.youtubeApiReady = true
    
    document.querySelectorAll('iframe[src*="youtube"]')
      .forEach(iframe => this.videos.push({
         dom: iframe,
         player: null,
         videoId: iframe.src.exec(matchId) || iframe.src.exec(matchId)[0]
       }))
  },
  createPlayers () {
    if (this.youtubeApiReady === false) return

    this.videos.forEach(v => {
      new YT.Player(v.dom.id, {
        videoId: v.videoId,
        events: {
          'onReady': function (event) {
            v.player = event.target
          }
        }
      })
    })
  },
  find (id) {
    return this.videos.find(v => v.id === id)
  },
  play (id) {
    const video = this.find(id)
    if (this.youtubeApiReady && video && video.player) {
      video.playVideo()
    }
  },
  pause (id) {
    const video = this.find(id)
    if (this.youtubeApiReady && video && video.player) {
      video.pauseVideo()
    }
  },
}

window.onYouTubeIframeAPIReady = function onYouTubeIframeAPIReady() {
  // YouTube client side script has been loaded
  YTManager.youtubeApiReady = true
  YTManager.createPlayers()
}

document.addEventListener("DOMContentLoaded", function() {
  // all iframes has been parsed by the browser
  YTManager.initialize()
});

当然你不能在没有ID的情况下调用YTManager.playYTManager.pause并等待YouTube脚本加载然后视频初始化完成。总而言之,真是一团糟。我相信你能想出一个更好的经理。我在工作中写过一个更好但也适用于完全不同的对象和要求,因此它不太适合通用 YouTube 视频管理器。不过上面那个是我现在播放器的要点

我建议从一开始就使用 iframe - 如果您的脚本出现任何问题,视频仍然可以播放,只是您无法控制它们。

Iframed YouTube 视频如下所示:

<iframe
  id="uniqueDOMElementID1"
  width="560"
  height="315"
  src="https://www.youtube.com/embed/bHQqvYy5KYo"
  frameborder="0"
  allow="autoplay; encrypted-media"
  allowfullscreen></iframe>

这是我的第二篇post,希望能解决您的问题。

我不是 100% 确定你的代码是如何工作的,但我怀疑......

It seems like a double instantiation of the YT.Player object, which will cause the YT.Player object unstable.

我自己也奋斗了很久(ps:我是业余程序员。)

例如,以下代码段修改自 Youtube Iframe API website and an example of how the second instantiation will break the player object try it! JS Bin

<!DOCTYPE html>
<html>

<body>
    <!-- 1. The <iframe> (and video player) will replace this <div> tag. -->
    <div id="player"></div>
    </br>
    <button onclick="instantiateOneMore()">
        Call
        <pre>new YT.Player('player')</pre>
    </button>
    <button onclick="pauseVideo()">
      pauseVideo();
    </button>
    <script>
        // 2. This code loads the IFrame Player API code asynchronously.
        var tag = document.createElement('script');

        tag.src = "https://www.youtube.com/iframe_api";
        var firstScriptTag = document.getElementsByTagName('script')[0];
        firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

        // 3. This function creates an <iframe> (and YouTube player)
        //    after the API code downloads.
        var player;

        function onYouTubeIframeAPIReady() {
            player = new YT.Player('player', {
                height: '390',
                width: '640',
                videoId: 'M7lc1UVf-VE',
                events: {
                    'onReady': onPlayerReady,
                    'onStateChange': onPlayerStateChange
                }
            });

        }


        let callTime = 0;
        // 4. The API will call this function when the video player is ready.
        function onPlayerReady(event) {
            event.target.playVideo();
            callTime ++;
            console.log(callTime);
            //document.querySelector('#dd').innerHTML = player.pauseVideo;
        }
      function pauseVideo(){
        player.pauseVideo();
      }
        instantiateOneMore = () => {
            player = new YT.Player('player', {
                height: '390',
                width: '640',
                videoId: 'M7lc1UVf-VE',
                events: {
                    'onReady': onPlayerReady,
                    'onStateChange': onPlayerStateChange
                }
            });
            //document.querySelector('#dd').innerHTML = player.pauseVideo;
        }

        // 5. The API calls this function when the player's state changes.
        //    The function indicates that when playing a video (state=1),
        //    the player should play for six seconds and then stop.
        var done = false;

        function onPlayerStateChange(event) {
            if (event.data == YT.PlayerState.PLAYING && !done) {
                /* setTimeout(stopVideo, 6000) */
                ;
                done = true;
            }
        }
        /* 
              function stopVideo() {
                player.stopVideo();
              } */
    </script>
</body>

</html>

此外,第二个 onPlayerReady() 甚至不会被调用。因此,如果您打算放置一些计数器来查看 new YT.Player(...) 被调用了多少次,您会怀疑它只被调用了一次。这使得效果远离调试。