抖音式上下滑动本质是分页切换而非滚动,核心在于vertical="true"、:current绑定与@change事件;视频播放需静音自动播+canplay后开声;须可视区渲染video防卡顿;交互层应覆盖video避免事件拦截。

swiper vertical="true" 是基础,但 current 和 change 事件才是控制核心
抖音式上下滑动的本质,不是“滚动”,而是“分页切换”——每次滑动都精准落到一个视频上。uni-app 的 swiper 组件天然支持这个逻辑,关键在于用对两个属性:vertical="true" 控制方向,:current="currentIndex" 绑定当前页索引,再靠 @change 事件捕获切换完成的时机。
常见错误是把 current 当成“正在滑动中的页”,其实它只在滑动结束、页面完全对齐后才更新。所以所有播放/暂停逻辑必须写在 onSwiperChange 里,而不是 @transition 或 @touchmove 中。
- 安卓和 H5 环境下,
current更新及时;iOS 上可能有微小延迟,别依赖它做实时进度条 - 不要在
onSwiperChange里直接调videoContext.play(),先确保 DOM 已就绪(可用$nextTick包一层) - 如果视频列表动态加载,记得在更新
videoList后手动重置currentIndex,否则容易越界或卡死
video 组件在 iOS 上“有声无画”?根源是 autoplay + muted 没配对
iOS Safari 对带声音视频的自动播放限制极严:没用户交互前,autoplay="true" + muted="false" 几乎必失败,表现为音频解码成功但视频帧卡在第一帧——这就是你看到“有声无画”的真实原因。
解决方案不是硬刚系统策略,而是顺应它:
- 首屏视频默认设
:autoplay="true"+:muted="true",iOS 允许静音自动播,画面能出 - 监听
video的@canplay或@loadedmetadata,一旦就绪,立刻调videoContext.mute(false)尝试开声(部分机型需用户点一下屏幕才真正生效) - 务必加上
playsinline webkit-playsinline x5-playsinline这三个属性,否则 iOS 微信里会强制全屏,破坏沉浸感
内存暴涨、滑动卡顿?别让几百个 video 标签同时挂 DOM 里
无限加载视频流时,很多人习惯一次性把全部 videoList 渲染进 swiper-item,结果页面滑到第 50 条时,内存占用飙升,swiper 开始掉帧甚至崩溃——这不是 bug,是浏览器对大量 <video></video> 标签的自然反制。
真实项目里必须做“可视区渲染”:
- 只让当前页、上一页、下一页共 3 个
video处于激活状态(v-if控制),其余用占位图或空view - 在
onSwiperChange里,根据新currentIndex动态切换v-if条件,旧视频调pause(),新视频调play() - 慎用
preload="auto",改用preload="metadata",减少预加载负担
双击点赞、右滑评论这些交互,别绑定在 video 上
video 标签在 iOS 和部分安卓 WebView 中会拦截 touchstart 和 click,导致双击事件不触发或响应迟钝。这不是你的代码问题,是浏览器对媒体元素的保护机制。
正确做法是把交互层盖在 video 上方:
- 用绝对定位的透明
view覆盖整个视频区域,所有手势(@tap、@touchstart、@touchend)都绑在这个 view 上 - 双击检测用
touchstart+ 时间差判断,别依赖@dblclick(H5 不支持) - 右滑评论这类操作,建议用
swiper自带的@touchmove做横向偏移判断,比监听 video 更稳定
最常被忽略的一点:iOS 下,如果视频正在播放且未静音,系统可能主动降频或暂停 JS 执行来保帧率——这意味着双击计时器可能不准,建议加个兜底逻辑,比如 touchend 后 300ms 内没触发第二次,就当单击处理。










