问题由来
-
在移动端开发中,像
ios
的微信浏览器、Safari
浏览器等,在网页进行滑动的时候会出现橡皮筋效果 -
橡皮筋效果: 当页面拉到尽头时还能继续拉动,露出浏览器的底色,松手会回弹回去
- 这样的效果一般只会出现在
ios
中,安卓倒没有这个问题
解决办法
- 首先想到的是
event.preventDefault()
阻止滑动的默认行为,但如果直接添加到页面上,整个页面就不会滚动了 - 那么只有达到临界值时,再阻止事件默认行为即可,于是只需判断页面是否滚动到了顶端和底部
原生写法:
javascript
(function () {
if (terminal() !== "ios") return;
let startY, endY;
window.addEventListener("touchstart", function (e) {
startY = e.touches[0].pageY;
}, { passive: false })
window.addEventListener("touchmove", function (e) {
endY = e.touches[0].pageY; // 记录手指触摸的移动中的坐标
// 判断是否为向上滑行为,并且页面已经到达顶端
const isCanUpslide = endY > startY && this.scrollY <= 0;
// 判断是否为向下滑行为,并且页面已经到达底部
const isCanDownslide =
endY < startY && this.scrollY + this.innerHeight >= document.body.scrollHeight;
// 手指滑动页面,到达两端都不能继续滑动
if ((isCanDownslide || isCanUpslide) && e.cancelable) e.preventDefault();
}, { passive: false });
})();
Jquery
写法:
javascript
// 使用 $.event.special 对象创建一个带有 passive 选项的自定义事件
$.event.special.touchmove = {
setup(_, ns, handle) {
this.addEventListener('touchmove', handle, { passive: false });
}
};
(function () {
if (terminal() !== "ios") return;
let startY, endY;
$(window)
.on("touchstart", function (e) {
startY = e.originalEvent.touches[0].pageY;
})
.on("touchmove", function (e) {
// e.preventDefault && e.preventDefault()
endY = e.originalEvent.touches[0].pageY; // 记录手指触摸的移动中的坐标
// 判断是否为向上滑行为,并且页面已经到达顶端
const isCanUpslide = endY > startY && $(this).scrollTop() <= 0;
// 判断是否为向下滑行为,并且页面已经到达底部
const isCanDownslide =
endY < startY && $(this).scrollTop() + $(this).height() >= $('body')[0].scrollHeight;
if ((isCanDownslide || isCanUpslide) && e.cancelable) e.preventDefault();
});
})();
为什么需要判断上下滑动行为?
- 当到达页面底部或顶部时,如果不判断滑动方向,此时无论做什么方向的滑动都会被阻止默认行为,这就造成页面不能滑动
- 也就是说不判断上下滑动方向,和直接阻止默认行为没有什么区别
注意:需要找准自己的滚动对象,不一定是
window
和body
判断设备方法
- 通过
navigator.userAgen
可以判断当前是不是ios
javascript
function terminal() {
var u = navigator.userAgent;
let osType;
if ((u && u.indexOf("Android") > -1) || u.indexOf("Linux") > -1) {
osType = "Android";
}
if (u && !!u.match(/(i[^;]+;( U;)? CPU.+Mac OS X/)) {
osType = "ios";
}
return osType;
}