最可行方案是 swiper + vertical="true",但需解决真机卡顿、黑屏、自动播放失败问题:关键在精准控制视频的加载、播放、暂停与销毁时机,而非仅滑动逻辑。

直接用 swiper + vertical="true" 是最可行的起点,但默认配置在真机上必卡顿、黑屏、自动播放失败——问题不在“怎么滑”,而在“什么时候加载、播放、暂停、销毁”。
swiper @change 不是实时滚动回调,别当它能捕获滑动过程
很多人把 @change 当成手指一动就触发的事件,其实它只在滑动完全停止、页面对齐完成后才触发。这意味着:
- 不能在
onSwiperChange里直接调this.$refs.video.play(),DOM 可能还没渲染完,得包一层this.$nextTick - iOS 上
current更新有微小延迟,别拿它算进度条或做同步动画 - 安卓和 H5 下响应及时;iOS 微信 WebView 中可能合并多次快速滑动,只触发一次
- 如果视频列表动态追加,更新
videoList后必须手动重置currentIndex,否则容易越界或卡死在空白页
video 自动播放失败?根本原因是 muted + playsinline 没配全
iOS 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()才真正可用
内存爆炸和卡顿,90% 来自“全量渲染 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.stop(),释放解码资源 - 小程序中慎用
autoplay:设为false,等@loadedmetadata触发后再play(),避免并发加载阻塞主线程
height: 100vh 在不同 WebView 下表现不一致,得手动适配
:vertical="true" 必须配 height: 100vh,但某些安卓 WebView 会把地址栏高度算进 vh,导致底部留白;iOS Safari 又可能因 URL 栏收起/展开动态改变 vh。
- 推荐用
height: calc(100vh - var(--window-top, 0px) - var(--window-bottom, 0px)),配合uni.getSystemInfoSync()动态注入 CSS 变量 - 小程序端更稳妥:用
uni.createSelectorQuery().selectViewport().boundingClientRect()获取真实可视高度 - H5 端可监听
window.innerHeight变化,但注意防抖,避免频繁重绘 - 务必给
video加object-fit: cover,并用!important强制生效(尤其微信小程序)
最常被忽略的是:没做 video 实例销毁、没限制预加载数量、没关闭非活跃项的 poster 动画——这些细节在真机上才是卡顿和崩溃的真正推手。











