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

实现对比滑块手柄的拖拽功能(不使用jQuery UI)

实现拖拽式对比滑块手柄(无需jQuery UI)

嘿,我帮你搞定这个问题啦!原来的代码是监听父容器的mousemove事件,导致鼠标只要在容器内移动就会触发手柄和面板变化,我们需要改成仅当按住手柄拖拽时才更新位置的逻辑。下面是完整的修改方案:

核心思路

  • 给手柄添加mousedown事件监听,标记拖拽状态为激活
  • 全局监听mousemove,但只有拖拽激活时才计算并更新位置
  • 监听mouseup和mouseleave事件,及时结束拖拽状态
  • 增加边界限制,防止手柄拖出容器范围
  • 加入拖拽时的视觉反馈,提升用户体验

修改后的完整代码

HTML(修正了原代码里的无效输入标签)

<div class="splitview skewed">
  <div class="panel bottom">
    <div class="content">
      <img src="https://images.pexels.com/photos/302804/pexels-photo-302804.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260" alt="Original">
    </div>
  </div>
  <div class="panel top">
    <div class="content">
      <img src="https://images.pexels.com/photos/707915/pexels-photo-707915.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260" alt="Duotone">
    </div>
  </div>
  <div class="handle"></div>
</div>

CSS(仅添加了拖拽光标提示,其余保持原样式)

/* Panels. */
.splitview {
  position: relative;
  width: 100%;
  min-height: 45vw;
  overflow: hidden;
}
.panel {
  position: absolute;
  width: 100vw;
  min-height: 45vw;
  overflow: hidden;
}
.panel .content {
  position: absolute;
  width: 100vw;
  min-height: 45vw;
  color: #FFF;
}
.panel.top .description {
  transform: translateY(-50%);
}
.panel.bottom .description {
  transform: translateY(-50%);
}
.panel .description {
  width: 25%;
  position: absolute;
  top: 50%;
  text-align: center;
  z-index: 999;
}
.panel .description h1 {
  margin-bottom: 0;
  font-size: 60px;
  line-height: .9;
}
.panel .description ul {
  text-align: left;
  margin-left: 4.5em;
}
.panel .description ul li {
  list-style: disc;
  font-size: 20px;
}
.panel .description h1, .panel .description p, .panel .description ul {
  color: #fff;
}
.panel img {
  box-shadow: 0 0 20px 20px rgba(0, 0, 0, 0.15);
  width: 100%;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 1;
  filter: brightness(0.3);
  transition: 0.2s ease;
}
.panel img:hover {
  filter: brightness(0.6);
}
.panel .description img {
  position: relative;
  top: 0;
  width: 60%;
  transform: none;
  left: 0;
  box-shadow: 0 0 20px 7px rgba(0, 0, 0, 0.15);
  margin-bottom: 1em;
  display: inline-block;
  filter: brightness(1);
}
.bottom {
  background-color: gray;
  z-index: 1;
}
.bottom .description {
  right: 10%;
}
.top {
  background-color: green;
  z-index: 2;
  width: 50vw;
}
.top .description {
  left: 10%;
}
/* Handle. */
.handle {
  height: 100%;
  position: absolute;
  display: block;
  background-color: #fff;
  width: 5px;
  top: 0;
  left: 50%;
  z-index: 3;
  cursor: ew-resize; /* 添加拖拽光标,提示用户可拖动 */
}
/* Skewed. */
.skewed .handle {
  top: 50%;
  transform: translateY(-50%);
  height: 200%;
  -webkit-transform-origin: top;
  -moz-transform-origin: top;
  transform-origin: top;
}
.skewed .top {
  margin-left: -1000px;
  width: calc(50vw + 1000px);
}
.skewed .top .content {
  margin-left: 1000px;
}

JavaScript(核心修改部分)

document.addEventListener('DOMContentLoaded', function() {
  var parent = document.querySelector('.splitview'),
      topPanel = parent.querySelector('.top'),
      handle = parent.querySelector('.handle'),
      skewHack = 0,
      isDragging = false; // 标记是否处于拖拽状态

  // 处理skewed样式的偏移量
  if (parent.classList.contains('skewed')) {
    skewHack = 1000;
  }

  // 按住手柄时激活拖拽状态
  handle.addEventListener('mousedown', function() {
    isDragging = true;
    // 拖拽时改变手柄颜色,给用户视觉反馈
    handle.style.backgroundColor = '#ff4444';
  });

  // 松开鼠标或移出容器时结束拖拽
  document.addEventListener('mouseup', endDrag);
  parent.addEventListener('mouseleave', endDrag);

  function endDrag() {
    if (isDragging) {
      isDragging = false;
      handle.style.backgroundColor = '#fff';
    }
  }

  // 鼠标移动时,仅拖拽激活状态下更新位置
  document.addEventListener('mousemove', function(event) {
    if (!isDragging) return;

    // 获取容器的位置和尺寸,计算鼠标在容器内的相对位置
    var containerRect = parent.getBoundingClientRect();
    var mouseXRelative = event.clientX - containerRect.left;
    // 限制在0-100%范围内,防止拖出容器
    var percentage = Math.max(0, Math.min(100, (mouseXRelative / containerRect.width) * 100));
    
    // 计算手柄和面板的目标位置
    var handleLeft = (containerRect.width * percentage) / 100;
    var topPanelWidth = handleLeft + skewHack;

    // 更新DOM样式
    handle.style.left = handleLeft + 'px';
    topPanel.style.width = topPanelWidth + 'px';
  });
});

关键修改点说明

  1. 拖拽状态控制:新增isDragging变量,只有按住手柄时才响应鼠标移动事件,解决了原代码“鼠标一动就触发”的问题
  2. 事件监听优化:全局监听mousemove,避免鼠标移出容器时拖拽中断;用统一的endDrag函数处理拖拽结束逻辑,代码更简洁
  3. 边界限制:通过Math.max和Math.min确保手柄始终在容器范围内,不会拖出屏幕
  4. 用户体验提升:添加拖拽光标提示和手柄颜色变化,让用户清晰知道这是可拖拽元素
  5. 修复HTML错误:移除了原代码中无效的输入标签,避免DOM解析问题

这样修改后,手柄就只会在你按住并拖拽时才会移动,完全符合你的需求,而且不需要依赖任何第三方库哦!

内容的提问来源于stack exchange,提问作者AaronS

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 10:19:10