最可行起点是swiper+vertical="true",但需严格管控video生命周期:@change中用$nextTick触发play()、动态列表重置currentIndex、iOS/微信端设muted=true并监听loadedmetadata再尝试开声、仅保留3个video实例防内存爆炸、小程序用cover-view抢touch事件。
直接用 swiper + vertical="true" 是最可行的起点,但真机上卡顿、黑屏、自动播放失败,90% 都是因为没控制好 video 实例的生命周期和平台行为差异。
它不是实时滚动回调,而是分页对齐完成信号——滑动还没停稳,DOM 可能都还没渲染出来。iOS 上 current 更新还有微小延迟,拿它算进度或同步动画会错位。
@change 回调里,而不是 @touchmove 或 @transition
onSwiperChange 中包一层 this.$nextTick,否则 this.$refs.video 可能为 undefined
currentIndex,否则容易越界或卡死在空白页iOS Safari 和微信 WebView 对带声视频的 autoplay 有硬性限制:没用户手势前,autoplay="true" + muted="false" 必然失败,表现就是“有声无画”或纯黑屏。
:muted="true" + :autoplay="true",让画面先出@loadedmetadata 或 @canplay,再调 videoContext.mute(false) 尝试开声(部分机型仍需用户点一下)playsinline、webkit-playsinline、x5-playsinline,否则 iOS 微信强制全屏autoplay,等 @loadedmetadata 触发后再 play(),避免并发加载阻塞主线程一次性把 100 条视频都塞进 swiper-item,等于让浏览器同时解码 100 个首帧——iOS Safari 卡死,小程序白屏,App 端内存飙升到 500MB+。
current - 1、current、current + 1 共 3 个 video 实例,其余用 v-if="false" 彻底移除 DOMpreload="metadata",而非 "auto";首次进入可视区才调 .load()
pause() + src = '' + load() 释放解码资源scroll-view 包 video,它会截断原生手势;改用普通 view + transform: translateY 模拟滚动微信小程序的 video 是原生组件,层级高于所有 webview 内容,touchstart/move 事件根本无法穿透到它上面——这不是 bug,是设计。
touchmove 就不触发,或只在边框空白处生效cover-view 盖一层透明遮罩,把滑动事件抢过来,再手动控制 video 的显隐与 src 切换ref + this.$refs.video.play(),不能用 uni.createVideoContext
nvue + 原生 video 组件,否则手势跟手、后台音频、低延迟都做不到真正难的不是“怎么切”,而是「什么时候销毁、什么时候预加载、什么时候强制暂停」——这些边界点稍有偏差,用户划着划着就卡住或黑屏了。