斜向图片滑块(Diagonal image slider)移动端无法交互问题咨询
问题
我开发了一个包含2张图片和1个滑块的斜切图片对比滑块(Diagonal image slider),桌面端可正常点击滑动,但移动端完全无法交互——滑块不可点击、无法滑动。我推测问题和mousedown、mouseup、mousemove这类鼠标事件有关,请问怎么适配到移动端?
以下是实现代码:
<style> #slider{ display: flex; align-items: center; justify-content: center; } .wrapper{ width: 30vw; height: 20vw; position:relative; overflow:hidden; box-shadow: 0 10px 20px rgba(0,0,0,0.1), 0 6px 6px rgba(0,0,0,0.2); } .before, .after { width:100%; height:100%; background-repeat:no-repeat; background-color: white; background-size: cover; background-position: center; position: absolute; top:0; left:0; pointer-events:none; overflow: hidden; } .content-image{ height:100%; } .after{ transform: skewX(-30deg) translate(-35vw); } .content-image.apres{ transform: skewX(30deg) translate(35vw); } .scroller{ width: 50px; height:50px; position: absolute; top:50%; transform:translateY(-50%); border-radius:50%; background-color: transparent; opacity:0.9; pointer-events:auto; cursor: move; box-sizing: border-box; border: 3px solid #fff; } .scroller:hover{ opacity:1; } .scrolling{ pointer-events:none; opacity:1; } .scroller__thumb{ margin:0; box-sizing: border-box; width:100%; height:100%; padding:5px; } .scroller:before, .scroller:after{ background: #fff; content:" "; display: block; width: 3px; height: 9999px; position: absolute; left: 50%; margin-left: -3.5px; z-index: 30; transition:0.1s; } .scroller:before{ top:95%; left:28%; transform-origin:top; transform:rotate(30deg) } .scroller:after{ bottom:95%; left:83%; transform-origin:bottom; transform:rotate(30deg) } </style> <main> <section id="slider"> <div class="wrapper"> <div class="before"> <img class="content-image" src="https://i.imgur.com/PNBfFe2.png" draggable="false"/> </div> <div class="after"> <img class="content-image apres" src="https://i.imgur.com/hxNAvu7.png" draggable="false"/> </div> <div class="scroller"> <svg class="scroller__thumb" xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><polygon points="0 50 37 68 37 32 0 50" style="fill:#fff"/><polygon points="100 50 64 32 64 68 100 50" style="fill:#fff"/></svg> </div> </div> </section> </main> <script> let active = false; var scrollers = document.querySelectorAll('.scroller'); scrollers.forEach(element => { element.addEventListener('mousedown',function scrolling(){ active = true; element.classList.add('scrolling'); }); }); document.body.addEventListener('mouseup',function(){ active = false; document.querySelector('.scroller').classList.remove('scrolling'); }); document.body.addEventListener('mouseleave',function(){ active = false; document.querySelector('.scroller').classList.remove('scrolling'); }); document.body.addEventListener('mousemove',function(e){ if (!active) return; let x = e.pageX; x -= document.querySelector('.wrapper').getBoundingClientRect().left; scrollIt(x); }); function scrollIt(x){ let transform = Math.max(0,(Math.min(x,document.querySelector('.wrapper').offsetWidth))); document.querySelector('.after').style.width = 'calc(' + transform + 'px + 35vw)'; document.querySelector('.scroller').style.left = transform-25+"px"; } scrollIt(300); </script>
问题原因
移动端不识别mousedown、mouseup、mousemove这类鼠标事件,需要替换为对应的触摸事件:touchstart(触摸开始)、touchend(触摸结束)、touchmove(触摸滑动)。另外触摸事件的坐标获取逻辑和鼠标事件不同,还需要处理页面滚动等默认行为的干扰。
修复方案
- 给滑块同时绑定
touchstart事件,复用鼠标事件的开始滑动逻辑; - 给
document.body绑定touchend事件,复用结束滑动逻辑; - 绑定
touchmove事件,通过e.touches[0].pageX获取触摸坐标,同时阻止默认行为避免页面滚动干扰; - 提前缓存DOM元素,减少重复查询提升性能;
- 提取通用逻辑为函数,减少代码冗余。
修改后的完整代码:
<style> #slider{ display: flex; align-items: center; justify-content: center; } .wrapper{ width: 30vw; height: 20vw; position:relative; overflow:hidden; box-shadow: 0 10px 20px rgba(0,0,0,0.1), 0 6px 6px rgba(0,0,0,0.2); } .before, .after { width:100%; height:100%; background-repeat:no-repeat; background-color: white; background-size: cover; background-position: center; position: absolute; top:0; left:0; pointer-events:none; overflow: hidden; } .content-image{ height:100%; } .after{ transform: skewX(-30deg) translate(-35vw); } .content-image.apres{ transform: skewX(30deg) translate(35vw); } .scroller{ width: 50px; height:50px; position: absolute; top:50%; transform:translateY(-50%); border-radius:50%; background-color: transparent; opacity:0.9; pointer-events:auto; cursor: move; box-sizing: border-box; border: 3px solid #fff; /* 禁用触摸默认行为,提升交互流畅度 */ touch-action: none; } .scroller:hover{ opacity:1; } .scrolling{ pointer-events:none; opacity:1; } .scroller__thumb{ margin:0; box-sizing: border-box; width:100%; height:100%; padding:5px; } .scroller:before, .scroller:after{ background: #fff; content:" "; display: block; width: 3px; height: 9999px; position: absolute; left: 50%; margin-left: -3.5px; z-index: 30; transition:0.1s; } .scroller:before{ top:95%; left:28%; transform-origin:top; transform:rotate(30deg) } .scroller:after{ bottom:95%; left:83%; transform-origin:bottom; transform:rotate(30deg) } </style> <main> <section id="slider"> <div class="wrapper"> <div class="before"> <img class="content-image" src="https://i.imgur.com/PNBfFe2.png" draggable="false"/> </div> <div class="after"> <img class="content-image apres" src="https://i.imgur.com/hxNAvu7.png" draggable="false"/> </div> <div class="scroller"> <svg class="scroller__thumb" xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><polygon points="0 50 37 68 37 32 0 50" style="fill:#fff"/><polygon points="100 50 64 32 64 68 100 50" style="fill:#fff"/></svg> </div> </div> </section> </main> <script> let active = false; // 提前缓存DOM元素,避免重复查询 const scrollers = document.querySelectorAll('.scroller'); const wrapper = document.querySelector('.wrapper'); const afterElement = document.querySelector('.after'); const scrollerElement = document.querySelector('.scroller'); // 通用开始滑动逻辑 function startScroll(element) { active = true; element.classList.add('scrolling'); } // 通用结束滑动逻辑 function endScroll() { active = false; scrollerElement.classList.remove('scrolling'); } // 绑定鼠标和触摸开始事件 scrollers.forEach(element => { element.addEventListener('mousedown', () => startScroll(element)); element.addEventListener('touchstart', (e) => { e.preventDefault(); // 阻止触摸默认行为(如缩放) startScroll(element); }); }); // 绑定鼠标和触摸结束事件 document.body.addEventListener('mouseup', endScroll); document.body.addEventListener('mouseleave', endScroll); document.body.addEventListener('touchend', endScroll); // 鼠标移动事件处理 document.body.addEventListener('mousemove', (e) => { if (!active) return; const x = e.pageX - wrapper.getBoundingClientRect().left; scrollIt(x); }); // 触摸移动事件处理 document.body.addEventListener('touchmove', (e) => { if (!active) return; e.preventDefault(); // 阻止页面滚动干扰 const x = e.touches[0].pageX - wrapper.getBoundingClientRect().left; scrollIt(x); }); function scrollIt(x){ const transform = Math.max(0, Math.min(x, wrapper.offsetWidth)); afterElement.style.width = `calc(${transform}px + 35vw)`; scrollerElement.style.left = `${transform - 25}px`; } scrollIt(300); </script>
额外优化说明
- 给
.scroller添加touch-action: none,明确告知浏览器无需处理该元素的触摸默认行为,避免不必要的交互冲突; - 缓存DOM元素减少重复查询,提升事件触发时的响应速度;
- 提取通用函数统一处理开始/结束滑动逻辑,让代码更易维护;
- 在触摸事件中调用
preventDefault(),避免页面滚动或缩放操作干扰滑块的正常交互。
内容的提问来源于stack exchange,提问作者chagatai
相关产品推荐
相关产品推荐

