記事内に商品プロモーションを含む場合があります
動画再生中だけスライダーの自動スライドを止める

Shopifyのテーマでよくスライダーに動画が設定できると思います。
今回は過去の案件で「自動でスライドさせて、動画が再生している間はスライダーの自動をとめる」ということをやりました。
その時は悩んでやっと実装できた記憶があるので、覚書としてブログに記録しておきます!
コードだけ先に知りたい方はこちら
// 👇️ using noConflict mode
const $jq = jQuery.noConflict();
(()=>{
let apiReadyResolve = null;
let apiReady = null;
function youtubeIframeAPIHelper_load() {
if (apiReady) return apiReady;
apiReady = new Promise(resolve => {
apiReadyResolve = resolve;
});
if (window.onYouTubeIframeAPIReady) {
// If onYouTubeIframeAPIReady is already defined, we need to call it
const {
onYouTubeIframeAPIReady
} = window;
window.onYouTubeIframeAPIReady = () => {
onYouTubeIframeAPIReady();
apiReadyResolve();
};
} else {
window.onYouTubeIframeAPIReady = apiReadyResolve;
}
if (!document.querySelector('#youtube-api-script')) {
const script = document.createElement('script');
script.setAttribute('id', 'youtube-api-script');
script.setAttribute('type', 'text/javascript');
script.setAttribute('src', '<https://www.youtube.com/iframe_api>');
document.body.appendChild(script);
}
if (window.YT && YT.loaded) {
apiReadyResolve();
}
return apiReady;
}
// load API then load Movies
// =====================================
window.addEventListener('load',()=>{
youtubeIframeAPIHelper_load().then(startSlidermMovie());
});
const parentSlider = document.querySelector('.slideshow--viewport').getAttribute('id');
const videoSlider = document.querySelectorAll('[data-video="youtube"]');
let sliderplayer;
let done = false;
function startSlidermMovie(){
videoSlider.forEach((item)=>{
item.lastElementChild.remove();
const player_id = 'slider-' + item.parentElement.getAttribute('data-slick-index');
item.querySelector('.js-youtubeinner').setAttribute('id',player_id);
const video_id = item.dataset.videoId;
setTimeout(function(){
sliderplayer = new YT.Player(player_id,{
videoId: video_id,
events: {
'onStateChange': onPlayerStateChange
}
});
item.classList.add('is-movie-loaded');
},100);
function onPlayerStateChange(event){
if (event.data == YT.PlayerState.PLAYING) {
pauseSlider();
}
if (event.data == YT.PlayerState.ENDED) {
startSlider();
}
}
function stopVideo() {
sliderplayer.stopVideo();
}
$jq('.slideshow--viewport').on('afterChange',function(){
stopVideo();
$jq(this).slick('slickPlay');
});
});
}
function pauseSlider(){
$jq('.slideshow--viewport').slick("slickPause");
}
function startSlider(){
$jq('.slideshow--viewport').slick("slickPlay");
}
// init Slider
// ----------------------------------------
$jq(function(){
$jq(document).ready(function () {
$jq(".slideshow--viewport").slick({
infinite: true,
autoplay: true,
dots: true,
autoplaySpeed: 2000,
pauseOnHover: true,
responsive: [
{
breakpoint: 600,
settings: {
arrows: false
}
},
]
});
});
});
})();
コードの解説
前提条件
前提条件として今回は「Atlantic」というテーマを使いました。(2022年秋頃だったので、今はコードが若干違うかもです💦)
また、スライダーはSlickを使いました。
nonConflict modeを使用する
// 👇️ using noConflict mode
const $jq = jQuery.noConflict();
テーマに記載があったので、そのまま使ってましたが…
例えば複数のバージョンのjQueryを混在して使わなければならないような場合などに$関数だけではなく、jQueryオブジェクトも含めて完全にグローバルの名前空間から除去します。
つまり、
$(funtion(){
// code...
});
を使えなくする、という意味ですね。
Youtube API を使って動画を再生する準備をする
このコードはYouTube IFrame Player API(YouTubeの動画をウェブページに埋め込むためのAPI)を扱うためのJavaScript関数です。この関数は、APIが準備完了するのを待って、その後の処理を行えるようにしています。
let apiReadyResolve = null; // YouTube APIの準備が完了したかどうか
let apiReady = null; // YouTube APIの準備が完了したかどうか
function youtubeIframeAPIHelper_load() {
if (apiReady) return apiReady; // apiReadyがNULLじゃなかったら return
apiReady = new Promise(resolve => {
apiReadyResolve = resolve;
});
if (window.onYouTubeIframeAPIReady) {
// If onYouTubeIframeAPIReady is already defined, we need to call it
const {
onYouTubeIframeAPIReady
} = window;
window.onYouTubeIframeAPIReady = () => {
onYouTubeIframeAPIReady();
apiReadyResolve();
};
} else {
window.onYouTubeIframeAPIReady = apiReadyResolve;
}
if (!document.querySelector('#youtube-api-script')) {
const script = document.createElement('script');
script.setAttribute('id', 'youtube-api-script');
script.setAttribute('type', 'text/javascript');
script.setAttribute('src', '<https://www.youtube.com/iframe_api>');
document.body.appendChild(script);
}
//もしYouTube APIが既にロードされていれば、Promiseをすぐに解決するためのチェック
if (window.YT && YT.loaded) {
apiReadyResolve();
}
return apiReady;
}
// load API then load Movies
// =====================================
window.addEventListener('load',()=>{
//読込完了したら、YouTubeAPIの読込確認し、終わり次第動画をスタートさせる
youtubeIframeAPIHelper_load().then(startSlidermMvoie());
});
動画をスタートさせる関数
const parentSlider = document.querySelector('.slideshow--viewport').getAttribute('id');
const videoSlider = document.querySelectorAll('[data-video="youtube"]');
let sliderplayer;
let done = false;
function startSlidermMovie(){
videoSlider.forEach((item)=>{
item.lastElementChild.remove();
const player_id = 'slider-' + item.parentElement.getAttribute('data-slick-index');
item.querySelector('.js-youtubeinner').setAttribute('id',player_id);
const video_id = item.dataset.videoId;
setTimeout(function(){
sliderplayer = new YT.Player(player_id,{
videoId: video_id,
events: {
'onStateChange': onPlayerStateChange
}
});
item.classList.add('is-movie-loaded'); // is-movie-loadedクラスを付与
},100);
});
}
[data-video="youtube"]
という属性をもっているスライダーを取得し、YouTubeIDから動画を再生させるコードです。
function onPlayerStateChange(event){
if (event.data == YT.PlayerState.PLAYING) {
//動画再生中は スライダーを一時停止させる
pauseSlider();
}
if (event.data == YT.PlayerState.ENDED) {
//動画再生終了したら、スライダーを再開させる
startSlider();
}
}
上記コードで、YouTubeプレイヤーの状態が再生中か再生終了かで、再度自動スライドを開始したり、一時停止させています。
スライダーを初期化
.slideshow--viewport
クラスをスライダーにします。
// init Slider
// ----------------------------------------
$jq(function(){
$jq(document).ready(function () {
$jq(".slideshow--viewport").slick({
infinite: true, //ループさせる
autoplay: true, //自動再生
dots: true, //ドットのナビゲーションあり
autoplaySpeed: 2000, // 自動スライドのスピード
pauseOnHover: true, //ホバーしたらスライドを一時停止させる
responsive: [
//レスポンシブの設定
{
breakpoint: 600,
settings: {
arrows: false
}
},
]
});
});
合わせて下記も関数として定義しておきます。
// スライダーを一時停止させる
function pauseSlider(){
$jq('.slideshow--viewport').slick("slickPause");
}
// スライダーを再開させる
function startSlider(){
$jq('.slideshow--viewport').slick("slickPlay");
}
また、スライダーを動かした後は動画再生を止め、自動スライドを再開させています。
function stopVideo() {
sliderplayer.stopVideo();
}
$jq('.slideshow--viewport').on('afterChange',function(){
stopVideo();
$jq(this).slick('slickPlay');
});
最後に
自動再生ありのスライダー+動画+動画再生中はスライドを止める、というよくありそうな仕様ですが、めちゃくちゃハマってしまったので備忘録として残しておきます…
参考になれば幸いです🙏