【slick vol3】
動的youtubeスライダーに、「YouTube Player API」をどうにか適用させたい
目次
どうも!こんにちは!
前々回、前回の続きにでslickの動的youtubeスライダーの続編となります。
前回うまくいかなかった、「YouTube Player API」を動的生成したyoutubeスライダーに適用させるをやっていきたいと思います。
それではスタートです!
前回の振り返り
前回の記事でjsonを読み込み、youtubeスライダーを動的に生成していました。
$.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;
}
}
こんな感じです。
YouTube Player APIが動的に生成するものに対してうまく動かなかったので、postMessageを使用しiframeの操作を行い、動画の一時停止をすることができたという感じです。
んで今回は「YouTube Player API」を使用してyoutube動画を制御しますので、postMessage部分の処理などはなくして、以下のソースを元にやっていきたいと思います。
$.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 id="player' + (dataIndex + 1) + '" 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) {
$(elems).slick({
dots: true,
// 以下slickのオプション設定のため割愛
});
}
YouTube Player APIを使う対応方法
まず、YouTube Player APIのリファレンスにある通りやってたら動かないです。
調べた結果、YouTube Player APIをajaxで呼び出すこと動くっぽい記事をstack overflowでチラッと見つけたのでそのやり方で実装してみました。
んでどこでajaxを呼び出すかですが、slideFire関数でスライドが生成される前に行うといけます。
なので今回の処理はすべて、slideFire関数内に記述していきます。
あと、YouTube Player APIを使用する場合、操作するiframeタグに固有のidを振る必要があるので、そこも降っておくようにしてください。
私の記述ですと以下のようにidを降っておくという感じです。
$createElem +=
'<iframe id="player' + (dataIndex + 1) + '" width="960" height="540"
実装
// slideFire関数
function slideFire(elems) {
// 動的挿入したiframeから、id属性と、youtubeIdを配列として生成する
const $iframes = $(elems).find('iframe');
const videoIds = [];
const iframeIds = [];
$iframes.each(function (i, elem) {
const iframeId = $(elem).attr('id');
const iframeSrc = $(elem).attr('src');
const iframeSrcSplit = iframeSrc.split('embed/');
const videoId = iframeSrcSplit[1].split['?'][0];
videoIds.push(videoId);
iframeIds.push(iframeId);
})
// YouTube Player APIのコードをajaxにてダウンロード
function getApi() {
$.ajax({
url: 'https://www.youtube.com/iframe_api',
dataType: 'script',
async: false,
success: function (data) { },
error: function (xhr, status, thrown) {
getApi()
}
})
}
getApi()
// YouTube Player APIのonYouTubeIframeAPIReadyを呼び出す
window.onYouTubeIframeAPIReady = function () {
loadPlayer(videoIds, iframeIds)
}
// 各youtube動画をYouTube Player APIで操作できるように、
// 動的生成した分new YT.Playerを生成する。
let players = [];
function loadPlayer(videoIdArray, iframeIdArray) {
for (let i invideoIdArray ) {
let VIDEOID = invideoIdArray[i]
let IFRAMEID = iframeIdArray[i]
IFRAMEID = new YT.Player(IFRAMEID, {
videoId: VIDEOID,
events: {
// YouTube Player APIで行いたいイベントを記載
onStateChange: onPlayerStateChange
}
})
players.push(IFRAMEID)
}
}
// YouTube Player APIで一時停止、再生をする関数
function onPlayerStateChange(event) {
if (event.data === 1) {
$('slide').slick('slickPause')
}
if (event.data === 2) {
$('slide').slick('slickPlay')
}
}
// slickのイベントをslick発火前に定義する
$(elems).on('beforeChange', function (event, slick, currentSlide) {
if (players[currentSlide].getPlayerState() === 1) {
players[currentSlide].pauseVideo()
}
})
$(elems).on('afterChange', function (event, slick, currentSlide) {
if (players[currentSlide].getPlayerState() === 2) {
players[currentSlide].playVideo()
}
})
// slick発火
$(elems).slick({
dots: true,
// 以下slickのオプション設定のため割愛
});
}
解説
動的生成したスライダーのidとyoutubeIdを取得する
ここは、動的生成したyoutubeのiframeにある、id属性と、src属性で設定されているyoutubeのvideoIdを取得する処理です。
id属性とvideoIdはYouTube Player APIを操作するために必要なので、そこだけを取得し配列に格納しています。
// 動的挿入したiframeから、id属性と、youtubeIdを配列として生成する
const $iframes = $(elems).find('iframe');
const videoIds = [];
const iframeIds = [];
$iframes.each(function (i, elem) {
const iframeId = $(elem).attr('id');
const iframeSrc = $(elem).attr('src');
const iframeSrcSplit = iframeSrc.split('embed/');
const videoId = iframeSrcSplit[1].split['?'][0];
videoIds.push(videoId);
iframeIds.push(iframeId);
})
YouTube Player APIをajaxで読みに行く
次にajaxですが、YouTube Player APIのソースを取りに行く関数を設定し呼び出します。
またajaxがerrorだった場合に、この関数をもう一度呼び出すようにしています。
// YouTube Player APIのコードをajaxにてダウンロード
function getApi() {
$.ajax({
url: 'https://www.youtube.com/iframe_api',
dataType: 'script',
async: false,
success: function (data) { },
error: function (xhr, status, thrown) {
getApi()
}
})
}
getApi()
YouTube Player APIで操作するためのYT.Player生成
YouTube Player APIで操作するために、動的生成したスライダー分のYT.Playerを生成しています。
合わせて、動画の再生・一時停止イベントとしてonPlayerStateChange関数を設定しています。
// 各youtube動画をYouTube Player APIで操作できるように、
// 動的生成した分new YT.Playerを生成する。
let players = [];
function loadPlayer(videoIdArray, iframeIdArray) {
for (let i invideoIdArray ) {
let VIDEOID = invideoIdArray[i]
let IFRAMEID = iframeIdArray[i]
IFRAMEID = new YT.Player(IFRAMEID, {
videoId: VIDEOID,
events: {
// YouTube Player APIで行いたいイベントを記載
onStateChange: onPlayerStateChange
}
})
players.push(IFRAMEID)
}
}
YouTube Player APIで操作するonPlayerStateChange関数の作成
onPlayerStateChange関数ですが、YouTube Player APIのリファレンスに載っている再生ステータスを参考に、
- youtubeが再生中であれば、slickを一時停止
- youtubeの再生が止まったらslickを再開
という処理を追加しています。
ここは要件になかったのですが、どうせ操作できるので追加しておいた感じです。
// YouTube Player APIで一時停止、再生をする関数
function onPlayerStateChange(event) {
if (event.data === 1) {
$('slide').slick('slickPause')
}
if (event.data === 2) {
$('slide').slick('slickPlay')
}
}
slickのイベントでスライダーの動きを検知して処理を実行
slick発火前に、beforeChange、afterChangeのイベントを登録します。
「beforeChange = スライドが変わる前」なので、スライドが変わる前にカレントスライドのyoutube動画が再生中であれば一時停止させます。
// slickのイベントをslick発火前に定義する
$(elems).on('beforeChange', function (event, slick, currentSlide) {
if (players[currentSlide].getPlayerState() === 1) {
players[currentSlide].pauseVideo()
}
})
「afterChange = スライドが変わったあと」なので、
スライドが変わったあとにカレントスライドのyoutube動画が一時停止中であれば、再生をさせます。
$(elems).on('afterChange', function (event, slick, currentSlide) {
if (players[currentSlide].getPlayerState() === 2) {
players[currentSlide].playVideo()
}
})
長々となってしまいましたが、処理的には以上です。
YouTube Player APIの https://www.youtube.com/iframe_api この読み込みがすんなり行けばいいのですが、どうもすんなり行かないようで。。
動的生成したものに対してYouTube Player APIを効かすには、ajaxで読み込みをするしかなさそうです。
何かご指摘やご意見ありましたら、お問い合せにてご連絡いただけると幸いです!
それでは次回もよろしく〜