最可行起点是 swiper + vertical="true",但需解决加载/播放/暂停/销毁时机问题:@change 非实时滚动回调、iOS current 延迟、video 必须 muted+playsinline、仅渲染可视区域 5 项、preload="none"、height 动态适配。
直接说结论:用 swiper + vertical="true" 是最可行的起点,但仅靠它默认配置一定会在真机上卡顿、黑屏、自动播放失败——核心问题不在“怎么滑”,而在“什么时候加载、播放、暂停、销毁”。
swiper 的 @change 事件不是实时滚动回调,而是分页对齐完成信号
很多人误以为 @change 能捕获滑动过程中的每一帧,其实它只在 swiper 完全停止、当前项完全对齐后才触发。这意味着:
- 不能在
@change里直接调this.$refs.video.play(),DOM 可能还没渲染完,得包一层this.$nextTick - iOS 上
current更新有微小延迟,别拿它算进度条或做动画同步 - 如果视频列表动态追加,更新
videoList后必须手动重置currentIndex,否则容易越界或卡死在空白页 - 安卓和 H5 下
@change响应及时;iOS 微信 WebView 中可能合并多次快速滑动,只触发一次
video 标签在 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()才真正可用
内存爆炸和卡顿,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 后,执行
pause()+src = ''+load(),释放解码资源 - 小程序中慎用
autoplay:设为false,等@loadedmetadata触发后再play(),避免并发加载阻塞主线程
swiper 在 H5 端的 height 计算陷阱
:vertical="true" 必须配 height: 100vh,但某些安卓 WebView 会把地址栏高度算进 vh,导致底部留白;iOS Safari 又可能因 URL 栏收起/展开动态改变 vh 值。
- 不要依赖纯
100vh,改用height: calc(100vh - var(--safe-area-inset-bottom))或 JS 动态计算 - swiper 内部
swiper-item必须设height: 100%,否则内容撑不开 - 避免在
swiper-item里放rich-text或未压缩大图,它们可能触发重绘抖动 - 真机调试时,务必关掉 Chrome DevTools 的“Emulate touch events”,否则手势行为失真
真正难的从来不是“怎么切视频”,而是判断“哪一刻该预加载、哪一刻该强制 pause、哪一刻该清空 src”。这些边界点差 100ms,用户划着划着就卡住或黑屏了——而它们在模拟器里几乎从不复现。



















