【slick vol2】
youtube動画が再生中であれば、動画を一時停止させる
目次
どうも!こんにちは!
前回の続きで、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」を適用させるを行いたいと思います。
それでは次回もよろしく〜。