You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

不使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 03:36:01