Vue.js で HTML Video の muted 属性が消える
会社に新しいプロジェクトがあり、私が独自に技術選定して開発を担当しました。プロジェクトの要件は英語の製品紹介サイトを作ることで、比較的シンプルで開発期間も長くなかったため、最終的に Nuxt フレームワークを使用して開発することにしました。
開発は概ね順調でしたが、途中で遭遇した 1 つの Bug にかなりの時間を費やしました。インターネットで長い間調べても、関連する内容はごくわずかしか見つからず、Vue の Github リポジトリの issues にあるものばかりでした。結局、問題の原因を見つけることはできませんでした。もちろん、これは Bug ではなく、フレームワーク自体がこのように設計されている可能性もあります。
以下は私の解決に至るまでの考え方です。もし皆さんに別の見解があれば、ぜひご指摘・交流いただければと思います。
問題の現象
製品紹介サイトのトップページには、全画面表示の video 要素があります。動画はデフォルトで自動再生されますが、ほとんどの最新のモダンブラウザのバージョンでこの機能を実現するには、video 要素に autoplay 属性を追加し、さらにデフォルトでミュート再生するための muted 属性を設定する必要があります。

初回のページ読み込み時には正常に自動再生されており、この時点では DOM 構造も Vue テンプレートに記述したコードと同じであることがわかります。
ここで一度ルートを製品ページに切り替え、再びトップページに戻ると問題が発生しました。元の video 要素にあった muted がなぜか消えてしまい、その結果、動画の自動再生も機能しなくなりました。

問題の分析
最初は Nuxt のルート切り替えの問題だと思い、Nuxt が提供する navigateTo() メソッドと、Vue Router が提供する $router.push() メソッドを使ってテストしましたが、どちらでも同じ問題が発生しました。
<div class="flex items-center justify-center">
<img
class="logo h-9 w-72 cursor-pointer"
src="/logo.png"
@click="$router.push('/')"
/>
</div>
2 回目はページに keepalive: true を設定してルートをキャッシュしてみましたが、それでも問題は解決しませんでした。さらに別の Bug まで引き起こされたため、深く追究することなく、ひとまずこの話は置いておくことにしました。
definePageMeta({
layout: 'full-screen',
keepalive: true,
})
3 回目は、video 要素に v-bind を使って muted 属性を動的にバインドしてみました。ref で定義した値でも、直接 :muted="true" とバインドしても、問題は解決できませんでした。
<video
src="car.mp4"
class="w-full h-full object-cover"
autoplay
loop
></video>
Nuxt の問題ではないかと疑い始めたため、4 回目は別の純粋な Vue プロジェクトを使ってテストしました。その結果、初回の読み込み時点ですでに muted 属性が失われていました。しかし奇妙なことに、動画は依然として自動再生できました。この奇妙な問題は、次第にますます謎めいていきました。

最終的に Vue の Github リポジトリで、まだ解決されていない issues を見つけました。そこでは私と同じ問題が発生していました。

これは 2022 年 10 月 12 日に作成された issues で、現在に至るまでまだクローズされていません。特筆すべき点として、その下には「Vue は本当にブラウザのネイティブ機能を壊すべきではない」という返信がありましたが、これは実際に Vue.js の Bug である可能性もあります。
問題の解決
最終的に、問題の原因にこだわるのをやめ、解決策の準備に取りかかりました。動的に属性をバインドしても問題を解決できないのであれば、最も原始的な方法を使うしかありません。つまり、DOM を操作して要素の再生イベントを発火させます。
onMounted(() => {
const videos = document.getElementsByTagName('video')
Array.from(videos).forEach((video) => {
video.play()
})
})
Vue のマウント完了後、document.getElementsByTagName('video') を使ってトップページにあるすべての動画要素を取得し、それぞれに対して再生イベントを発火させます。これにより、ルートを切り替えてから再びトップページに戻った場合でも、動画の自動再生を維持できるようになります。
この方法で問題を簡単に解決することはできますが、これが最終的な解決策ではないように感じます。問題の核心はやはりフレームワーク側にあるはずです。どなたか詳しく調査していただき、私にもご教示いただければ幸いです。
コメント
(0)まだコメントはありません