本日も業務内で発生した問題を解決したので、記載していきます。
今回は、videoタグで動画を埋め込み、それをjsで制御する。と、いったものです。
正直、動画の再生制御は実装したことがなく、調べながらの作業でした。
多くはありませんが、動画を採用しているサイトは見かけるので、今回学習したことを記録しておこうと思います。
- JavaScriptでvideoを操作する基本(再生・停止・イベント)
- 動画の再生コントロールをカスタマイズする方法
- 自動再生がブロックされる条件と対処
- 実際の案件でのコード例
JavaScriptでvideoを操作する基本。
実装に入る前に、JavaScriptからvideoタグを操作するときの基本をまとめておきます。
ここさえ押さえておけば、あとは組み合わせるだけです。
まずは要素を取得する。
最初につまずきやすいのがここです。
jQueryのオブジェクトのままでは、play()やpause()は使えません。
動画の操作はDOM要素に対して行うので、素のJavaScriptで取得するか、jQueryなら.get(0)で取り出してあげます。
// 素のJavaScript
const video = document.querySelector('#opv');
// jQueryを使っている場合
const video = $('#opv').get(0);この記事の後半のコードで $('#opv').get(0) と書いているのは、そのためです。
再生と停止。
video.play(); // 再生
video.pause(); // 一時停止停止して最初に戻したい場合は、currentTimeを0にします。
video.pause();
video.currentTime = 0;再生中かどうかを判定する。
「再生中か」を直接見るプロパティはありません。
あるのは逆のpausedなので、これで判定します。
if (video.paused) {
video.play();
} else {
video.pause();
}再生ボタンと一時停止ボタンを1つにまとめたいときは、この形になります。
よく使うプロパティ。
| プロパティ | 内容 |
| paused | 停止中なら true になります。 |
| currentTime | 再生位置(秒)です。値を代入すると、その位置に移動します。 |
| duration | 動画全体の長さ(秒)です。 |
| volume | 音量です。0〜1の範囲で指定します。 |
| muted | true でミュートになります。 |
| playbackRate | 再生速度です。1が等倍です。 |
| loop | true でループ再生になります。 |
注意したいのがdurationです。
動画の情報が読み込まれるまで取得できないので、後述のloadedmetadataイベントの中で取得してください。
よく使うイベント。
| イベント | 発火するタイミング |
| loadedmetadata | 長さやサイズなどの情報が読み込まれたとき。 |
| play | 再生が始まったとき。 |
| pause | 一時停止したとき。 |
| ended | 最後まで再生し終わったとき。 |
| timeupdate | 再生位置が変わったとき。再生中に何度も発火します。 |
| volumechange | 音量が変わったとき。 |
video.addEventListener('ended', function () {
// 再生が終わったときの処理
});この記事の後半でも、endedを使って「動画が終わったら非表示にする」処理を書いています。
自動再生がブロックされる条件。
実務でいちばんハマるのがここです。
ブラウザは、音が出る動画を勝手に再生させてくれません。
自動再生させたい場合は、mutedが必須です。
<video src="movie.mp4" autoplay muted playsinline></video>iPhoneでは、これに加えてplaysinlineも必要です。
付けないと、再生した瞬間に全画面のプレーヤーが立ち上がってしまいます。
なお、play()はPromiseを返すので、ブロックされたときの処理を書くこともできます。
video.play().catch(function () {
// 自動再生がブロックされたときの処理
// 再生ボタンを表示するなど
});ここまでが基本です。
ここからは、実際の案件でこれらを組み合わせて実装した例を紹介していきます。
JavaScriptを使用して動画をコントロールする。
最初にvideoタグについて詳しく知りたい方は、以下のリンクからご覧ください。
今回は、videoタグについて書いていこうと思います。 先日、案件でメインビジュアルに動画を設置するというものがあり、さらにPCとSPで動画を切り替えて欲しいと言う要望もありました。レスポンシブに対応させる方法など調べて実装してみた[…]
動画の制御というと、controls属性を使って、動画をコントロールする方法がありますが、今回はそうでなく、デザインを重視した方法でコントロールする方法をご紹介します。
あと、今回の動画は、メインビジュアルに設置します。
CSSアニメーションでメインビジュアルを表現するのではなく、その代わりに動画を設置する。といった形です。
動画終了後に動画は非表示にして、動画終了の画面と同じ画像が現れるようにしていきます。
以上のことを踏まえて、実装に必要な機能を整理していきます。
必要な機能。
まずは、必要な機能、条件みたいなものを書き出しておきます。
- 動画の再生終了後は、動画を非表示。
- 動画の再生中には、動画をスキップさせるためのボタンを設置する。
- 動画再生終了後には、動画のリプレイボタンを設置して、再度再生可能な状態にする。
- 動画は、PCとSPで表示させる画像が違う。
冒頭でお伝えした機能にプラス、動画をコントールするための機能を実装していきます。
2〜4の条件は、動画を設置するにあたり、ご依頼主様よりいただいた条件です。
srcの切り替えは、.attr();を使用。.play();と.pause();で動画のをコントロールする。(完成コード)
<div id="opv-wrap">
<div id="movie_skipBtn"><a>SKIP</a></div>
<video id="opv" autoplay muted playsinline src=""></video>
</div>
<div id="movie_replayBtn"><a>REPLAY</a></div>それでは、この条件をそれぞれ解決したコードを先に紹介しておきます。
const opvWrap = $('#opv-wrap');
const opVideo = $('#opv').get(0);
const video = $('#opv');
const main = $('main');
const replayBtn = $('#movie_replayBtn');
const skipBtn = $('#movie_skipBtn');
const windowSp = window.matchMedia('(max-width:799px)').matches;
movieSwitch();
$(document).on('lead', function() {
setTimeout(function() {
opvWrap.fadeIn(1000);
}, 500);
});
opVideo.addEventListener('ended', function() {
movieStop();
});
replayBtn.on('click', function() {
opVideo.play();
opvWrap.fadeIn();
$(this).fadeOut();
skipBtn.fadeIn();
main.removeClass('js-movieEnd');
});
skipBtn.on('click', function() {
opVideo.pause();
movieStop();
});
function movieStop() {
$('#opv-wrap').fadeOut();
main.addClass('js-movieEnd');
replayBtn.fadeIn();
}
function movieSwitch() {
if(windowSp) {
video.attr("src", "/sp/movie/mv.mp4");
} else {
video.attr("src", "/movie/mv.mp4");
}
}それでは、それぞれ解説していきます。
.attr();でvideoのsrcを切り替える。
動画は、pcとspで違うものを再生させます。
レスポンシブに切り替えなくてはならないので、jsでウインドウ幅を検知させ、.attr();でsrcの中を切り替えます。
const windowSp = window.matchMedia('(max-width:799px)').matches;
movieSwitch();
function movieSwitch() {
if(windowSp) {
video.attr("src", "/sp/movie/mv.mp4");
} else {
video.attr("src", "/movie/mv.mp4");
}
}ifで条件分岐されていますので、条件を変更・追加してあげれば、細かく動画を切り替えることも可能です。
PC→タブレット→SPといいた具合に。
videoタグにsourceを使用してmediaで動画を切り替える方法もある。
jsは、めんどくさい。ので、HTMLで切り替える方法もありますが・・・
iPhone(Safari)ではうまく動作しませんでした。
<video id="opv" autoplay muted playsinline>
<source src="/movie/mv.mp4" type="video/mp4" media="(max-width: 799px)">
<source src="/movie/mv.mp4" type="video/mp4">
</video>ブレイクポイントを media=”(max-width: 799px)としていすることで、読み込まれる動画が切り替わるのですが、なぜか切り替わりません。
Androidは、問題なくsourceで切り替えることができました。
$(document).on(‘lead’, function(){});を使用して全て読み込まれてから動画を表示させる。
続いてjsですが、まずは動画を格納している要素全体を取得しておきます。
<div id="opv-wrap">
<div id="movie_skipBtn"><a>SKIP</a></div>
<video id="opv" autoplay muted playsinline src=""></video>
</div>
<div id="movie_replayBtn"><a>REPLAY</a></div>上記でいうところの「id=”opv-wrap”」の部分ですね。
$(document).on('lead', function() {
setTimeout(function() {
opvWrap.fadeIn(1000);
}, 500);
});js発火のタイミングの注意点としては、Webサイト全体が読み込まれてから動画を表示させるようにします。
そしないと、Webサイトが読み込まれている最中に動画の再生が始まってしまい、表示されたときには動画が途中からになっていることがあります。
特にメインジュアルに動画を置いている場合、早い段階で読み込まれてしまうので、Webサイトが完全に読み込まれていない状態で動画がスタートしてしまうことが多くありました。
その結果、動画も再生はされているがみることができず、やっと見れるようになっても動画が進んでしまっていました。
setTimeoutは、念のための対策です。
Webサイト読み込み完了から少しタイムラグを設けることで、動画再生のタイミングをサイトが読み込まれたあと、さらに遅延させています。
タイムラグを設けることで、一呼吸おいてから動画の再生を始めることができます。
発火タイミングが.ready();ではいけない理由。
結論から言うと、別に.ready();でもいいです。
ただ、やはりすべて読み込まれてから動画の再生をしてからの方がいいと思います。
理由としては、ページの表示速度です。
今回は、動画をメインビジュアルに設置しているため、ページ下部の画像よりも先に動画が読み込まれて再生が始まります。
すると、動画の再生中にページの読み込まれる関係か、表示速度が遅くなっている気がします。(気のせいかな?)
その点、.on(‘lead’);は全て(HTML構造、画像などのリソース)が読み込まれたあとに動画が再生するので、ページが完全に表示されてから再生が始まります。
動画の影響でページの読み込み速度が遅くなることもありませんし、動画も最初から再生されます。
以上のことから、私は.on(‘lead’);で発火させています。
addEventListener(‘ended’, function() {});で動画の終了を検知する。
上記までで、動画が無事に読み込まれ、再生されました。
次は、動画が終了したときの動作です。
$(document).on('lead', function() {
setTimeout(function() {
opvWrap.fadeIn(1000);
}, 500);
});.on(‘lead’, function() {});で、動画を再生させたら再生終了後は、動画要素全体を非表示にしたいので、「addEventListener(‘ended’, function() {});」の記述を使います。
opVideo.addEventListener('ended', function() {
$('#opv-wrap').fadeOut();
main.addClass('js-movieEnd');
replayBtn.fadeIn();
});endedで動画の再生の終了を検知して、再生が終了したら要素を非表示にして、その後に「リプレイボタン(replayBtn.fadeIn();)」を表示させています。
.play();で意図的に動画を再生させる。
続いては、再生が完了した動画をリプレイボタンで、再度再生させます。
replayBtn.on('click', function() {
opVideo.play();
opvWrap.fadeIn();
$(this).fadeOut();
skipBtn.fadeIn();
});ここで、ポイントとなるのは.play();です。
.play();は、動画を再生させることができます。
動画の要素を取得して、そこに.play();を指定してあげます。
スキップされたときは、.pause();で動画を一時停止させる。
最後は、動画の一時停止です。
冒頭でお話ししましたが、videoタグにcontrols属性をつけることで動画をコントロールすることはできますが、デザイン的な問題があります。
そんなときは、自身で作ったボタン要素に.pause();を指定してあげて、動画をコントロールします。
skipBtn.on('click', function() {
opVideo.pause();
$('#opv-wrap').fadeOut();
replayBtn.fadeIn();
});動画を再生するのと同時に、リプレイボタンは非表示にしてあげます。
共通部分は、関数化しておくと見やすくなる。
以上、今回の条件をクリアして、動画をコンロールすることができました。
「動画の制御」ということで、少し難しく感じたかもしれませんが、やってみると初心者でもできるほど簡単な記述で制御することができます。
最後になりましたが、今回記述したjsの内容は、共通部分を関数にすることで、実行の記述をもっと簡素化することもできます。
例えば、下記のように動画の要素を非表示にしたとき、リプレイボタンを表示、スキップボタンを非表示にする。といった動作は一連の動作になります。
function movieStop() {
$('#opv-wrap').fadeOut();
main.addClass('js-movieEnd');
replayBtn.fadeIn();
}共通の部分は、関数にすると繰り返し同じ動作を書かなくていいので、少し長いjsを書くときは意識してみるといいかもしれません。
使用するときは、使いたい処理の中で関数を宣言してあげるだけです。
movieStop();可読性が上がるので、試してみてください。
