移动端自动播放的痛点
解决方案:Vue 3 实战
1. 模板结构:区分PC与移动端
<template>
<div :class="{ 'pc-styles': !isMobile, 'mobile-styles': isMobile }">
<!-- PC端:弹窗视频 -->
<div v-if="!isMobile && showModal" class="modal-overlay">
<video ref="videoRef" :src="videoUrl" autoplay loop muted playsinline webkit-playsinline @loadedmetadata="onVideoLoaded" @canplay="handleCanPlay">
您的浏览器不支持视频播放。
</video>
<!-- ... PC端控制按钮 ... -->
</div>
<!-- 移动端:内联视频 -->
<div v-if="isMobile" class="mobile-video-container">
<video ref="mobileVideoRef" :src="videoUrl" autoplay loop muted playsinline webkit-playsinline @loadedmetadata="onVideoLoaded" @canplay="handleCanPlay">
您的浏览器不支持视频播放。
</video>
<!-- ... 移动端控制按钮 ... -->
</div>
</div>
</template>
关键点:
- playsinline 和 webkit-playsinline : 这两个属性对于iOS Safari和部分Android Chrome浏览器至关重要,确保视频以内联形式播放。
- muted : 默认静音是自动播放的前提。
- autoplay 和 loop : 声明自动播放和循环。
2. Script Setup:核心逻辑
import { ref, onMounted, onUnmounted, computed } from 'vue'
// 响应式数据
const videoRef = ref<HTMLVideoElement | null>(null)
const mobileVideoRef = ref<HTMLVideoElement | null>(null)
const isMobile = ref(false)
const isMuted = ref(true) // 默认静音
// ... 其他响应式数据
// 检测移动端
const detectMobile = () => {
const userAgent = navigator.userAgent.toLowerCase()
const mobileKeywords = ['mobile', 'android', 'iphone', 'ipad']
isMobile.value = mobileKeywords.some(keyword => userAgent.includes(keyword)) || window.innerWidth <= 768
}
// 视频加载元数据完成
const onVideoLoaded = () => {
const currentVideo = isMobile.value ? mobileVideoRef.value : videoRef.value
if (currentVideo) {
currentVideo.muted = isMuted.value // 确保静音状态
if (isMobile.value) {
tryAutoPlay(currentVideo) // 移动端尝试播放
}
}
}
// 视频可以播放时
const handleCanPlay = () => {
const currentVideo = isMobile.value ? mobileVideoRef.value : videoRef.value
if (currentVideo && isMobile.value) {
tryAutoPlay(currentVideo)
}
}
// 尝试自动播放 (核心)
const tryAutoPlay = async (videoElement: HTMLVideoElement) => {
try {
videoElement.muted = true // 再次确保静音
await videoElement.play() // 尝试播放
console.log('视频自动播放成功')
} catch (error) {
console.warn('自动播放失败,可能需要用户交互:', error)
// 自动播放失败,设置用户交互后播放的逻辑
const playOnInteraction = async () => {
try {
await videoElement.play()
console.log('用户交互后播放成功')
// 成功播放后移除事件监听器
document.removeEventListener('touchstart', playOnInteraction)
document.removeEventListener('click', playOnInteraction)
} catch (e) {
console.warn('用户交互后播放仍然失败:', e)
}
}
// 监听touchstart和click事件,once确保只触发一次
document.addEventListener('touchstart', playOnInteraction, { once: true })
document.addEventListener('click', playOnInteraction, { once: true })
}
}
// 切换静音状态
const toggleMute = async () => {
isMuted.value = !isMuted.value
const currentVideo = isMobile.value ? mobileVideoRef.value : videoRef.value
if (currentVideo) {
currentVideo.muted = isMuted.value
// 如果是移动端且取消静音,确保视频在播放
if (isMobile.value && !isMuted.value) {
try {
if (currentVideo.paused) {
await currentVideo.play()
}
} catch (error) {
console.warn('取消静音时播放失败:', error)
}
}
}
}
// 生命周期钩子
onMounted(() => {
detectMobile()
window.addEventListener('resize', detectMobile)
// ... 其他初始化逻辑
})
onUnmounted(() => {
window.removeEventListener('resize', detectMobile)
// ... 清理逻辑
})
核心逻辑解析 :
- detectMobile() : 通过UserAgent和屏幕宽度判断是否为移动设备。
- onVideoLoaded() 和 handleCanPlay() : 在视频元数据加载完成或视频可以播放时,都会调用 tryAutoPlay() 尝试播放。
- tryAutoPlay() : 这是实现自动播放的关键函数。
1. 强制静音 : videoElement.muted = true 。
2. 尝试播放 : await videoElement.play() 。现代浏览器返回一个Promise,可以通过它判断播放是否成功。
3. 失败降级 : 如果 play() 方法抛出异常(通常是因为浏览器策略限制),则进入 catch 块。
4. 用户交互监听 : 在 catch 块中,为 document 添加 touchstart 和 click 事件监听器。使用 { once: true } 确保这些监听器在首次触发后自动移除,避免不必要的性能开销和逻辑冲突。
5. 交互后播放 : 当用户触摸屏幕或点击时,再次尝试播放视频。
- toggleMute() : 切换静音状态时,如果是在移动端且用户取消了静音,会检查视频是否暂停,如果是则尝试播放。这是因为某些浏览器在取消静音后可能会暂停视频。
深度解析与最佳实践
1. playsinline 的重要性 :对于iOS Safari, playsinline 是内联播放的必备属性。没有它,视频通常会强制全屏播放。
2. muted 是金钥匙 :绝大多数情况下,静音是移动端自动播放的先决条件。
3. Promise-based play() : HTMLMediaElement.play() 方法返回一个Promise。成功播放时,Promise会resolve;如果因浏览器策略等原因无法播放,Promise会reject。利用这一点可以优雅地处理播放成功与失败的逻辑。
4. 用户交互的必要性 :当所有自动播放尝试都失败后,引导用户进行一次交互(如点击屏幕)来启动播放是最后的可靠手段。确保这个交互是用户友好的,并且只在必要时触发。
5. 渐进增强 :我们的策略是首先尝试理想的自动播放,如果失败,则逐步降级到需要用户交互的方案。这提供了最佳的用户体验。
6. 测试,测试,再测试 :移动端浏览器种类繁多,行为各异。在多种设备和浏览器上进行充分测试至关重要。
7. 考虑网络状态 :在弱网环境下,视频加载可能会很慢。可以添加加载指示器,或者监听视频的 waiting 和 playing 事件来提供更好的用户反馈。
8. 避免滥用 watch :在Vue 3中,优先使用 computed 和事件驱动的逻辑,而不是过度依赖 watch 来响应状态变化,以获得更好的性能和可维护性。
发表评论
全部评论 (0)