最可行方案是 swiper + :vertical="true",但需解决加载/播放/销毁时机问题:@change 非实时、ios current 延迟、video 必须 muted+playsinline、按需渲染 5 个 item、preload="none"、动态计算高度。

直接用 swiper + :vertical="true" 是最可行的起点,但默认配置在真机上必然卡顿、黑屏、自动播放失败——问题不在“怎么滑”,而在“什么时候加载、播放、暂停、销毁”。
swiper 的 @change 事件不是实时滚动回调,别在这儿写 play()
很多人误以为 @change 能捕获滑动过程中的每一帧,其实它只在 swiper 完全停止、当前项完全对齐后才触发。这意味着:
- 不能在
onSwiperChange里直接调this.$refs.video.play(),DOM 可能还没渲染完,得包一层this.$nextTick - iOS 上
current更新有微小延迟,别拿它算进度条或做动画同步 - 安卓和 H5 下响应及时;iOS 微信 WebView 中可能合并多次快速滑动,只触发一次
- 如果视频列表动态追加,更新
videoList后必须手动重置currentIndex,否则容易越界或卡死在空白页
video 必须 muted+playsinline,否则 iOS/H5 首屏就是黑屏
这不是 bug,是 Safari 和微信 WebView 的硬性限制:没有用户手势触发前,autoplay="true"+muted="false" 必然失败,表现就是“有声无画”或纯黑屏。
- 首屏视频必须设
:muted="true"+:autoplay="true",让画面先出来 - 监听
@loadedmetadata或@canplay,再尝试videoContext.mute(false)开声(部分机型仍需用户点一下屏幕) - 所有
video必须加playsinline、webkit-playsinline、x5-playsinline,否则 iOS 微信里强制全屏 - H5 端更狠:首次页面加载后,必须等用户触发一次
touchstart,后续play()才真正可用
别一次性渲染全部 video,内存爆炸就从这开始
一次性把 100 条视频都塞进 swiper-item,等于告诉浏览器:“请同时解码 100 个视频首帧”。iOS Safari 直接卡死,小程序白屏,App 端内存飙升到 500MB+。
- 只保留
current - 2到current + 2共 5 个swiper-item,其余用v-if="false"彻底移除 DOM - 每个
video加preload="none",首次进入可视区才调.load() - 滑出视口 500ms 后,执行
context.pause()+context.src = '',释放解码资源 - 小程序中慎用
autoplay:设为false,等@loadedmetadata触发后再play(),避免并发加载阻塞主线程
swiper 的 height 在 H5 端有计算陷阱,别写死 100vh
:vertical="true" 必须配 height: 100vh,但某些安卓 WebView 会把地址栏高度算进 vh,导致底部留白;iOS Safari 又可能因 URL 栏收起/展开动态改变 vh。
- 在
onLoad阶段用uni.getSystemInfoSync().windowHeight动态计算容器高度 - 给
swiper加style="height: {{swiperHeight}}px",比固定值更适配多机型 - 避免用
scroll-view包video,它会截断原生video的手势事件;改用普通view+position: sticky或transform: translateY模拟滚动
最常被忽略的三个点:没做 video 实例销毁、没限制预加载数量、没关闭非活跃项的 poster 动画——它们不报错,但会在真机上悄悄拖垮性能。










