不使用jQuery实现拖拽滑块惯性连续滑动及流畅拖动效果咨询
滑块拖拽惯性效果实现方案
核心修改思路
- 新增速度计算逻辑:拖拽过程中实时记录位移与时间差,计算松手时的瞬时滑动速度
- 新增惯性动画逻辑:松手后通过
requestAnimationFrame实现带阻尼的减速滑动,速度低于阈值时自动停止 - 修复CSS冲突问题:移除重复的transition声明,避免不必要的属性过渡导致滑动卡顿
完整修改后代码
JavaScript代码
const slider = document.querySelector('.items'); let isDown = false; let startX; let scrollLeft; // 新增惯性相关变量 let velocity = 0; let lastX = 0; let lastTime = Date.now(); let animationId = null; // 新增惯性滑动函数 function inertiaScroll() { // 阻尼系数,数值越小减速越快 velocity *= 0.95; slider.scrollLeft -= velocity; // 速度小于0.5时停止动画 if (Math.abs(velocity) > 0.5) { animationId = requestAnimationFrame(inertiaScroll); } } slider.addEventListener('mousedown', (e) => { isDown = true; slider.classList.add('active'); startX = e.pageX - slider.offsetLeft; scrollLeft = slider.scrollLeft; // 拖拽开始时清空之前的惯性动画 cancelAnimationFrame(animationId); lastX = e.pageX; lastTime = Date.now(); velocity = 0; }); slider.addEventListener('mouseleave', () => { isDown = false; slider.classList.remove('active'); // 离开元素时触发惯性 inertiaScroll(); }); slider.addEventListener('mouseup', () => { isDown = false; slider.classList.remove('active'); // 松手时触发惯性 inertiaScroll(); }); slider.addEventListener('mousemove', (e) => { if (!isDown) return; e.preventDefault(); const x = e.pageX - slider.offsetLeft; const walk = (x - startX) * 2; slider.scrollLeft = scrollLeft - walk; // 计算实时速度 const currentTime = Date.now(); const deltaTime = currentTime - lastTime; const deltaX = e.pageX - lastX; if (deltaTime > 0) { velocity = deltaX / deltaTime * 2; // 系数可调整惯性强度 } lastX = e.pageX; lastTime = currentTime; }); slider.addEventListener('touchstart', (e) => { isDown = true; slider.classList.add('active'); const touch = e.touches[0]; startX = touch.pageX - slider.offsetLeft; scrollLeft = slider.scrollLeft; cancelAnimationFrame(animationId); lastX = touch.pageX; lastTime = Date.now(); velocity = 0; }, { passive: true }); slider.addEventListener('touchend', () => { isDown = false; slider.classList.remove('active'); inertiaScroll(); }); slider.addEventListener('touchcancel', () => { isDown = false; slider.classList.remove('active'); inertiaScroll(); }); slider.addEventListener('touchmove', (e) => { if (!isDown) return; e.preventDefault(); const touch = e.touches[0]; const x = touch.pageX - slider.offsetLeft; const walk = (x - startX) * 2; slider.scrollLeft = scrollLeft - walk; // 计算实时速度 const currentTime = Date.now(); const deltaTime = currentTime - lastTime; const deltaX = touch.pageX - lastX; if (deltaTime > 0) { velocity = deltaX / deltaTime * 2; } lastX = touch.pageX; lastTime = currentTime; }, { passive: false });
CSS代码(修复冲突)
.items { height:600px; padding: 100px; width:100%; overflow-x: hidden; overflow-y: hidden; white-space: nowrap; user-select: none; cursor: pointer; /* 移除重复的transition,仅给需要过渡的属性加动画,避免影响scrollLeft */ transition: transform 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275), background 0.2s; transform: scale(0.98); will-change: transform, scrollLeft; /* 新增scrollLeft到will-change优化渲染 */ position: relative; background: rgba(255,255,255,0.1); font-size: 0; perspective: 500px; } .items.active { background: rgba(255,255,255,0.2); cursor: grabbing; cursor: -webkit-grabbing; transform: scale(1); } .item { width:300px; margin:0 80px 0 80px; height: calc(100% - 40px); display: inline-flex; align-items: center; justify-content: center; font-size: 80px; font-weight: 100; color:rgba(0,0,0,0.5); box-shadow: 5px 3px 4px 10px black; }
HTML代码无需修改
参数调整说明
- 阻尼系数
0.95:数值越大惯性滑动距离越长,可在0.9-0.98区间调整 - 速度系数
2:数值越大松手后滑动速度越快,可根据需求调整 - 停止阈值
0.5:数值越大惯性停止越早,可根据流畅度需求调整
内容的提问来源于stack exchange,提问作者Phoenixia
相关产品推荐
相关产品推荐

