【slick vol2】
youtube動画が再生中であれば、
動画を一時停止させる

  • 【slick vol2】
    youtube動画が再生中であれば、動画を一時停止させる

    JavaScript

    どうも!こんにちは!

    前回の続きで、youtube動画をスライダーにした際に学んだことを書いていきたいと思います。

    今回は、

    • HTMLファイル内にiframeで配置したyoutubeスライダー、jsonデータを読み込んで動的生成したyoutubeスライダーどちらも、youtubeが再生中の際にスライドを移動させたらyoutubeを一時停止させる。

    という内容です。

    Googleが提供しているiframe操作ができるYouTube Player APIというの使えばよさそうですが、
    それでは対応できなかったので、苦しい中やった対応を共有できればと思います。

    それではスタートです!

    HTMLファイル内にiframeで配置したyoutubeスライダー

    まず、上記タイトル通りHTMLファイル内
    iframeで配置したyoutubeスライダーからですが、
    「YouTube Player API」を使えば再生・一時停止などはできます。

    「YouTube Player API」のリファレンスに書かれているように、

    // 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: '360',
              width: '640',
              videoId: 'M7lc1UVf-VE',
              events: {
                'onReady': onPlayerReady,
                'onStateChange': onPlayerStateChange
              }
            });
          }
    
          // 4. The API will call this function when the video player is ready.
          function onPlayerReady(event) {
            event.target.playVideo();
          }

    この方法であればyoutube動画の操作ができます。

    ただし、今回youtube動画は複数のスライダーになっているため、onYouTubeIframeAPIReady関数内のvideoIdなどは事前にdata属性などで付与してから配列として取得し、その分forEachなどで回して設定してください。

    あと、この記述はloadイベント内で記述すると効かないです。

    onYouTubeIframeAPIReady関数を発火させるのは、「https://www.youtube.com/iframe_api」このAPIが読まれた直後に実行されるっぽいのですが、このAPIは非同期で読まれるようで、いつ読まれているかが分からないためです。

    jsonデータを読み込んで動的生成したyoutubeスライダー

    これがやっかいです。

    というのも、先程のyoutubeスライダーはすでにHTMLにiframeが配置されているので、要素の取得をして「YouTube Player API」で操作をするというのができます。

    ただこちらは、動的にiframeを生成しさらにスライダーにまでするので、
    どうしても「iframeが挿入されてyoutube動画の準備ができたら且つスライダーが生成されたら」というのを待ってからじゃないと、各youtube動画を「YouTube Player API」で操作することができません。。

    んで、先程お伝えしたように「https://www.youtube.com/iframe_api」は非同期で読まれて、読まれた直後にonYouTubeIframeAPIReady関数を発火させるようなので、「YouTube Player API」のリファレンス通りでは動的に生成したyoutubeスライダーで操作はできません。

    対処法

    iframeにはpostMessageとやらを送信して、iframeに命令を送ることができるようなので、こちらで対応してみました。

    動的にスライダーを生成するので一応json取得の方から貼っていきます。

    $.ajax({
              url: '取得するjsonデータへのパス',
              type: 'get',
              dataType: 'json',
              cache: false,
            })
              .done(function (res) {
                const resDatas = res;
                createHtml(resDatas, $('.your-class'), num); // jsonデータを用いて、動的にiframeを生成させる関数
                slideFire($('.your-class')); // createHtml関数で生成したiframeをスライダーにする関数
              })
              .fail(function () {
                console.log('ajax fail');
              });
    
    //  createHtml関数
    function createHtml(datas, elems, nums) {
          const $createElem = '';
          $.each(datas, function (dataIndex, data) {
            const videoId = data.id.videoId;
            $createElem += '<div class="slider">';
            $createElem += '<div class="slider-video">';
            $createElem +=
              '<iframe width="960" height="540" src="https://www.youtube.com/embed/' +
              videoId +
              '?enablejsapi=1" title="YouTube video player" frameborder="0" class="slider-iframe"></iframe>';
            $createElem += '</div>';
            $createElem += '</div>';
          });
          $(elems).append($createElem);
        }
    
    //  slideFire関数
    function slideFire(elems) {
    // スライドする前にpostMessageを送って、youtube動画を一時停止にさせる
      $(elems).on('beforeChange', function (event, slick) { 
        slick = $(slick.$slider)
        playPauseVide(slick, 'pause')
      })
      $(elems).slick({
        dots: true,
       // 以下slickのオプション設定のため割愛
      });
    }
    
    // iframeにpostMessageを送る関数
    function postMessageToPlayer(player, command) { 
      if (player === null || command === null) return;
      player.contentWindow.postMessage(JSON.stringify(command), '*');
    }
    
    // 動画の一時停止関数
    function playPauseVide(slick, control) { 
      let currentSlide, player;
      currentSlide = slick.find('.slick-current');
      player = currentSlide.find('iframe').get[0]
      switch (control) { 
        case 'pause';
          postMessageToPlayer(player, {
            event: 'command',
            func: 'pauseVideo',
            args: '',
          })
          break;
      }
    }

    こんな感じです。
    簡単に解説します。

    slideFire

    この関数はslickを発火させる関数です。
    また、slickのイベントであるbeforeChangeイベントで「スライダーが動く直前に動画を一時停止する」、というpostMessageをiframe側に送信しています。

    //  slideFire関数
    function slideFire(elems) {
    // スライドする前にpostMessageを送って、youtube動画を一時停止にさせる
      $(elems).on('beforeChange', function (event, slick) { 
        slick = $(slick.$slider)
        playPauseVide(slick, 'pause')
      })
      $(elems).slick({
        dots: true,
       // 以下slickのオプション設定のため割愛
      });
    }

    注意点としては、slickのイベントはslickを起動する前に行うということです。

    playPauseVide

    この関数は、カレント表示のスライダーのiframeに、動画を一時停止させるpostMessageを送る関数です。

    カレントスライダーの取得と、そのスライダー内のiframeの取得をして、postMessageで動画を一時停止させるメッセージを送ってます。

    // 動画の一時停止関数
    function playPauseVide(slick, control) { 
      let currentSlide, player;
      currentSlide = slick.find('.slick-current');
      player = currentSlide.find('iframe').get[0]
      switch (control) { 
        case 'pause';
          postMessageToPlayer(player, {
            event: 'command',
            func: 'pauseVideo',
            args: '',
          })
          break;
      }
    }

    postMessageToPlayer

    この関数は実際にiframe側にpostMessageを送る関数です。
    細かく何をしているかまでは、調べきれませんでした。。

    // iframeにpostMessageを送る関数
    function postMessageToPlayer(player, command) { 
      if (player === null || command === null) return;
      player.contentWindow.postMessage(JSON.stringify(command), '*');
    }


    このPostMessageを使うことで「YouTube Player API」でなくても、youtube動画の操作は多少することができました。

    別で「YouTube Player API」をどうにか、動的生成スライダーに適用できないかを調べて、対応できそうになったので、次回は動的生成スライダーに「YouTube Player API」を適用させるを行いたいと思います。

    それでは次回もよろしく〜。

記事をシェアする