感谢<https://www.cnblogs.com/cuncunjun/p/7493782.html>的启发,方法很有用!
好几个月以前,我写了一个类似于自动回复那种的客服页面,嵌入到公司开发的app里。上周测试突然找到我,说
页面在滑动的时候,输入框也会跟着上下滑动,而这个问题只在ios系统上出现,Android没问题。测试的同学希望我
做点什么,把页面固定住,不要随着手指的滑动上下动。修改前的界面大概像下面的示意图这样:
经过百度,知道了这叫做橡皮筋效果,是ios系统在引入网页时专有的一种效果.要去掉这种效果,可以采用fixed
布局,也可以监听touchmove事件,利用event.preventDefault()解决。第一种方法我尝试了,觉得不是很好用,而
且页面的滑动变得卡顿,橡皮筋效果还是时而出现,因此考虑第二种办法。
event.preventDefault()说白了就是监听touchmove,在手指滑动屏幕的时候,禁止掉页面随手指滑动而滚动的
默认事件。看到这里问题就来了,我的页面是一个聊天页面,聊天记录还是可以通过上下滑动手指来查看的,如果禁止
了滚动页面,岂不是动不了了?
所以,需要给preventDefault()增加一个限制条件,即只有页面滑动到顶部或者底部了,才调用preventDefault(),
阻止对应的滑动事件。那么,如何判断页面是否已经滑动到两端呢?利用clientHeight、scrollHeight和scrollTop
三个属性。
我们对这三个属性做一下区分(对页面中同一个元素而言):
clientHeight是元素展示在页面中的固定高度;
scrollHeight是当元素中内容很多,出现滚动条时,元素中内容的实际高度,scrollHeight>=clientHeight,
当不需要滚动页面时,二者相等;
scrollTop是当页面滚动时,页面中内容向上卷起来的距离,即内容的顶部距离固定的元素顶部的距离。
由上面的定义可知,当页面滑动到顶部时,scrollTop为0,当页面出现橡皮筋时,scrollTop小于0.当页面滑动
到底部时,scrollTop + clientHeight = scrollHeight。因此,我们可以写下这样的代码:
mounted(){
//判断是不是ios
let u = navigator.userAgent;
let isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端
//如果是ios,执行下面的代码
if(isiOS){
//因为要禁止整个页面的滑动,所以定义一个box,里面装有chatBody和foot两个子元素
const box = document.getElementById("longbox");
const chatBody = document.getElementById("chatContainer");
//开始滑动,此处使用box元素的事件监听,来禁止整个页面的滑动
box.addEventListener("touchmove", function(e){
//如果滑到顶端或底端,禁止滑动
if(chatBody.scrollTop<=0 || chatBody.scrollTop + chatBody.clientHeight>=chatBody.scrollHeight){
e.preventDefault();
}
})
}
}
测试一下,发现一个问题,的确当滑动到顶部时,无法继续上滑了,但同时也无法下滑了。为什么?因为e.preventDefault()组织的是所有方向上的滑动事件,所以当页面滑到顶端或者底端时,禁止了一切的滑动,页面就动不了了。因此,考虑改进代码,增加一个上滑或者下滑的判断:
mounted(){
//判断是不是ios
let u = navigator.userAgent;
let isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端
//如果是ios,执行下面的代码
if(isiOS){
//因为要禁止整个页面的滑动,所以定义一个box,里面装有chatBody和foot两个子元素
const box = document.getElementById("longbox");
const chatBody = document.getElementById("chatContainer");
var startY,endY; //定义滑动的起点和终点
//监听touchstart事件,记录滑动起点的位置
box.addEventListener("touchstart", function(e){
startY = e.touches[0].pageY;
})
//开始滑动,此处使用box元素的事件监听,来禁止整个页面的滑动
box.addEventListener("touchmove", function(e){
endY = e.touches[0].pageY; //记录此时的滑动y轴坐标
//页面向上滑动
//页面滚动上去的长度scrollTop
if(endY>startY&& chatBody.scrollTop<=0){
e.preventDefault();
}
//页面向下滑动
//页面的总长度(包括滚动上去的部分)scrollHeight
if(endY<startY&& chatBody.scrollTop + chatBody.clientHeight>=chatBody.scrollHeight){
e.preventDefault();
}
})
}
}
再测试,解决橡皮筋效果~
啰嗦一下,上面的代码是最终解决版的代码,但其实中间还是遇到了一个小坑的,就是在多层div嵌套时,父容器的
高度可能不定,由子容器撑开。比如我这个聊天页面,父容器box只标注了height:100%; container包括两个子容
器:子容器chat是需要滑动的div,不定高,还有一个高度为47px的foot子容器。这时候,需要禁止整个页面(其
实就是父容器)的滑动,子容器chat可以滑动,所以,要监听box的事件,禁止的也是box的滑动,而是否滑动到页
面顶端/底端的判断依据,则需要对chat的scrollHeight和scrollTop进行判断。
第一次写文章,说的不对的地方,还请多多指正!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。