首屏滑动引导图可用纯 CSS + JavaScript 实现:用 transform: translateX() 位移、touchstart/touchmove 拦截滑动、scroll-behavior: smooth 或 requestAnimationFrame 做平滑切换,配合 setTimeout 控制自动轮播与 isUserInteracting 状态解耦交互,结构扁平、事件不被遮挡,兼顾性能与兼容性。
直接上手做就行,不需要引入 Swiper 或 Vue-Awesome-Swiper 这类重型轮播组件——首屏引导图本质就是几张图 + 左右滑、点选、自动轮播三件事,自己写 50 行 JS 就够用,加载快、无兼容风险、可控性强。
关键点在于:用 transform: translateX() 做位移,用 touchstart/touchmove 拦截原生滑动,禁掉 body 的默认滚动行为,否则 iOS 上一滑就页面跟着动。
width: 100vw,容器设 display: flex + width: max-content
scroll-behavior: smooth 配合 scrollLeft 做平滑跳转(仅需支持现代浏览器时)requestAnimationFrame 手动插值动画setTimeout + clearTimeout 控制,切页时立刻重置计时器常见错误是把引导图包在 position: relative 的父容器里,再加一堆 z-index 层级,结果 touchstart 在子元素上触发不了,或者被其他绝对定位按钮吞掉事件。
推荐结构极简:
立即学习“前端免费学习笔记(深入)”;
<div class="onboarding"> <div class="slides"> <div class="slide"><img src="1.jpg"></div> <div class="slide"><img src="2.jpg"></div> <div class="slide"><img src="3.jpg"></div> </div> <div class="dots"></div> <button class="next-btn">→</button></div>
.slides 必须设 overflow: hidden,否则滑动时看到多余内容.slide 不要用 float 或 inline-block,只用 flex 或 transform 定位.dots 动态生成,用 data-index 绑定当前页,别用 class 名如 dot-active 硬编码touchcancel 和快速连滑iOS Safari 在手指快速来回滑两下后,经常触发 touchcancel 而不是 touchend,导致松手后位置卡住、动画不收尾。这是真坑,网上很多示例没处理这个。
touchstart 记录 pageX,touchmove 计算偏移量并实时更新 transform
touchend 和 touchcancel 都要进同一个收尾逻辑:判断滑动距离是否超过阈值(如 50px),决定是切换页还是回弹element.style.transition = 'none' 关闭过渡,防止上一次动画干扰transition: transform 0.3s ease-out
用户手动滑了一页,自动轮播还在倒计时,3 秒后突然又切走——体验极差。根本原因是轮播计时器和用户交互状态没解耦。
isUserInteracting 标志位,在 touchstart、click、keydown 时置为 true
if (!isUserInteracting) { gotoNext() }
setTimeout,3 秒后把 isUserInteracting 设回 false
setInterval,它无法感知用户是否还在操作,容易堆叠多个定时器真正难的不是滑动动画,而是滑动过程中用户点了跳过按钮、切了 App、锁了屏、又回来——这些边界情况全靠状态标记+及时清理来兜住。写完先在 iOS 微信里连点十次“跳过”,再横竖屏切三次,没问题才算过关。