背景
在项目中我们经常会遇到滚动穿透的问题如下:
弹窗首先有一个遮罩层,然后遮罩层中间有一块内容区域,内容区域里边有一部分内容也可以滚动
问题代码
页面内容页面内容页面内容页面内容页面内容页面内容页面内容页面内容页面内容页面内容页面内容
复制代码
其中图片的高度是超过一屏幕的,意思说可以产生滚动
.popup {
position: fixed;
left: 0;
right: 0;
bottom: 0;
top: 0;
}
.mask {
width: 100%;
height: 100%;
background: rgba(0, 0, 0, .5);
}
.content {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
background: #fff;
width: 60%;
height: 200px;
border-radius: 3px;
box-sizing: border-box;
padding: 10px;
overflow: auto;
}
复制代码
遮罩层滚动穿透
可以看到在滑动遮罩层的时候,底部内容也可以滚动
中间内容滚动穿透
当我们给中间的框加了一个固定的高度,但是中间内容超过了框的高度。我们试图滚动中间内容的时候就会出现以下的情况:
可以看到这么一个行为:正常的滚动时候没问题,但是一旦滚动到页面底部的时候,我们继续滚动就发现背景页面也发生了滚动
解决方案
使用overflow: hidden
当这个弹窗出现的时候就让body设置overflow:hidden,高度设置为height: 100vh; 弹窗消失的时候在这个样式改回去伪代码如下:
// 表示弹窗打开
popup.addEventListener('show', () => {
body.style.overflow = 'hidden';
body.style.height = '100vh'
})
// 表示弹窗关闭
popup.addEventListene('close', () => {
body.style.overflow = 'auto';
body.style.height = 'auto'
})
复制代码
这样就能避免产生滚动穿透,但是这种方案存在一个问题,就是当页面超过一屏幕的时候并且页面已经滚动了一部分距离,这时候当我们打开弹窗的时候,页面就滚动到了顶部,关闭弹窗的时候页面也就停留在了顶部,这种方式对用户来说不够友好,为什么刚才还在顶部,现在就滚动到了顶部呢。所以针对这种情况可以采用在打开弹窗的时候记住滚动的位置,然后在关闭的弹窗时候让页面滚动到先前的位置,伪代码如下:
let scrollTop;
// 表示弹窗打开
popup.addEventListener('show', () => {
// 记住当前的滚动位置
scrollTop = body.scrollTop;
body.style.overflow = 'hidden';
body.style.height = '100vh'
})
// 表示弹窗关闭
popup.addEventListene('close', () => {
// 把当前的滚动位置设置为先前的scrollTop
body.scrollTop = scrollTop;
body.style.overflow = 'auto';
body.style.height = 'auto'
})
复制代码
移动端触摸事件
首先解决遮罩层的滚动,这个很简单只需要下面这张代码
$('.mask').on('touchmove', (e) => {
e.preventDefault();
})
复制代码
就是直接阻止遮罩层的touchmove事件。
然后是内容区域的滚动,首先进行行为分析,在上面我们可以看到,在内容区域滚动的时候,只要没有到达顶部或者底部的时候,滚动内容区域背景是不会跟着滚动的,但是当我们滚动到底部的时候继续向下滑动,页面就发生了滚动。根据这个行为大概就可以总结出方案,当页面滚动到底部或者顶部的时候组织他的默认滚动行为不就行了吗。 下面是他的具体代码
$('.content').on('touchstart', function (e) {
const targetTouches = e.targetTouches || []
if (targetTouches.length > 0) {
const touch = targetTouches[0] || {};
startY = touch.clientY;
}
})
$('.content').on('touchmove', function(e) {
const targetTouches = e.targetTouches;
const scrollTop = this.scrollTop;
if (targetTouches.length > 0) {
const touch = targetTouches[0] || {};
const moveY = touch.clientY;
if (scrollTop === 0 && moveY > startY) {
e.preventDefault();
} else if (scrollTop === scrollHeight - offsetHeight && moveY < startY) {
e.preventDefault();
}
}
})
复制代码
思路很简单,就是监听touchstart和touchmove事件,判断是否滚动到顶部还有顶部。首先记录touchstart的时候手指距离顶部的距离,在移动的过程中在获取手相对屏幕的一个位置,通过这两个位置比较,判断现在是向上滑动还是向下滑动,从而判断是否到达了边界情况。
使用better-scroll
这个就比较简单了,使用第三方库他这个核心原理就是直接让滚动的元素设置overflow: hidden,
然后内容区域超过容器区域,使用translate代替原生的scroll事件来进行滚动,所以需要注意的是打开弹窗时候better-scroll需要知道这个弹窗的内容区域的高度才能正确的滚动(那时候用这个总有小伙伴遇到这个问题)
上面就是常用的几种解决滚动弹窗的方法。个人比较常用的是第二种方法,1:相对第一种用户体验好;2: 相对第三种,不用引入额外的库。
关于找一找教程网
本站文章仅代表作者观点,不代表本站立场,所有文章非营利性免费分享。
本站提供了软件编程、网站开发技术、服务器运维、人工智能等等IT技术文章,希望广大程序员努力学习,让我们用科技改变世界。
[【经验】移动端滚动穿透]http://www.zyiz.net/tech/detail-141877.html