必须手动控制video播放:监听swiper@transition预判下一项、@change确认当前项,用ref精准操作current±1项的load()/play()/pause(),并针对iOS/安卓真机限制做超时回退和v-show优化。

uni-app 中用 swiper 实现抖音式上下滑动视频列表,核心是「自动播放 + 滑动暂停 + 预加载临近项」
直接结论:不能只靠 video 组件原生能力,必须配合 swiper 的 current 变化监听 + 手动控制 play()/pause(),且需规避 iOS 微信/APP 内 autoplay 失效、swiper 惯性滑动导致的“卡顿播放”问题。
为什么 swiper 的 autoplay 和 video 的 autoplay 都不靠谱
因为它们根本不是为「单页多视频流场景」设计的:
-
swiper的autoplay只控制翻页节奏,不感知视频是否加载完成或是否在可视区;滑动中它可能还在播上一个video,而当前项还没 ready -
video的autoplay在 iOS(尤其微信 WebView)和部分安卓 APP 中被强制禁用,即使加了muted也不一定生效,必须用户手势触发后才可播放 - 滑动过快时,
swiper的change事件会延迟触发(尤其惯性滚动),导致视频切换滞后甚至跳过中间项
怎么让当前项自动播放、其他项静音暂停(含预加载逻辑)
关键不是“等滑到再处理”,而是「提前一帧准备」——监听 swiper 的 transition 过程,在即将进入可视区前就初始化视频,并在完全离开前暂停:
- 用
swiper的@transition+@change双事件配合:@transition获取实时偏移,判断「下一个将要显示的索引」;@change确认最终停留位置 - 每个
video绑定独立 ref(如videoRefs[index]),避免 DOM 查找开销 - 预加载策略:对
current - 1、current、current + 1三项调用load()(仅加载元数据,不自动 play),iOS 下可触发后续play()的权限链 - 播放时机:在
@change后检查video.readyState === 4(HAVE_ENOUGH_DATA),再play();失败则 fallback 到click触发(加个半透明播放按钮层)
// template 片段
<swiper @transition="onSwiperTransition" @change="onSwiperChange" :current="currentIndex">
<swiper-item v-for="(item, idx) in videoList" :key="item.id">
<video
:ref="el => videoRefs[idx] = el"
:src="item.url"
muted
:autoplay="idx === currentIndex"
@loadedmetadata="() => onVideoLoaded(idx)"
@error="onVideoError(idx)"
/>
</swiper-item>
</swiper>
真机调试最容易翻车的三个点
这些坑不踩一次很难意识到:
- iOS APP(非 H5)中,
video.play()必须在用户 touchstart 后 1s 内调用,否则静音也失败 —— 解决办法:在swiper的@touchstart里记个时间戳,@change后立刻play(),超时则显示「点击播放」浮层 - 安卓低端机频繁销毁/重建
videoDOM(尤其是v-if控制显隐),导致内存暴涨卡顿 —— 改用v-show+display: none,并手动pause()+load()重置 - 预加载太多项(比如 current±2)会让网络请求堆积,首屏变慢 —— 建议只预加载 ±1,且用
IntersectionObserver(uni-app 3.0+ 支持)做懒加载兜底
滑动视频列表不是组件堆砌,而是播放状态、生命周期、平台限制三者的实时博弈。最稳的做法永远是:把「播放」当作一个需要明确授权、明确时机、明确兜底的用户操作,而不是一个可以全自动的属性。


















