持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第25天,点击查看活动详情
什么是滚动穿透?就是我们搞一个遮罩层,然后遮罩层上下滑动,底下也跟着滚动。
组织时间冒泡到body上可以吗?答案是不行,因为我们的滚动是浏览器原生实现的效果。而且scroll事件一般也是不冒泡的。我们滚动或者手机在屏幕上滑动的时候,有两种可能:一种是整个viewport触发滚动,这种的eventtarget就是document,另外就是元素里面触发了滚动,这个滚动的主题就是元素啦。所以滚动穿透是一个正常的浏览器行为。
我们可以禁止掉touchmove事件,但是这个会禁止掉整个的dom,如果dom里面有滚动咋办呢?
我们可以有选择性地禁止滚动事件,判断一下滚动发生的dom,符合我们的要求再禁止滚动,但是!如果滚动到头尾那么久又不行了。所以我们需要判断是否滑动到头部或者尾部。
所以我们的代码如下:
let loc = 0;
scrollElement.addEventListener('touchstart', (e) => {
loc = e.target.clientY;
})
scrollElement.addEventListener('touchmove', e=> {
const clientY = e.targetTouches[0].clientY - initialY;
if (
el.scrollTop + el.clientHeight >= el.scrollHeight &&
clientY < 0
) {
return e.preventDefault();
}
if (el.scrollTop <= 0 && clientY > 0) {
return e.preventDefault();
}
})
这样我们的整体思路,就是当需要禁止touchmove事件的时候,就把这个函数拿出来调用一下,禁止全局的滚动事件,除了指定的滚动区域。然后如果蒙层消失,立马恢复取消监听touchmove事件,通过这种方式,就能够实现禁止滚动且允许局部的滚动。
需要注意的是,我们一共监听了比较多的事件,取消监听的时候最好把所有的监听事件都给取消监听了,这样能避免内存泄露。
整个流程就是监听,不允许滚动,然后取消监听,允许滚动。