实现对比滑块手柄的拖拽功能(不使用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'; }); });
关键修改点说明
- 拖拽状态控制:新增
isDragging变量,只有按住手柄时才响应鼠标移动事件,解决了原代码“鼠标一动就触发”的问题 - 事件监听优化:全局监听
mousemove,避免鼠标移出容器时拖拽中断;用统一的endDrag函数处理拖拽结束逻辑,代码更简洁 - 边界限制:通过
Math.max和Math.min确保手柄始终在容器范围内,不会拖出屏幕 - 用户体验提升:添加拖拽光标提示和手柄颜色变化,让用户清晰知道这是可拖拽元素
- 修复HTML错误:移除了原代码中无效的输入标签,避免DOM解析问题
这样修改后,手柄就只会在你按住并拖拽时才会移动,完全符合你的需求,而且不需要依赖任何第三方库哦!
内容的提问来源于stack exchange,提问作者AaronS
相关产品推荐
相关产品推荐

