下面的代码是一个纯 JavaScript 的解决方案,从几个来源中提炼出来,它们位于底部。
如果您愿意更改页面结构,则仅 CSS/HTML 选项可能适合您。
此外,草案 CSS 属性 scroll-boundary-behavior 正在标准化并添加到 Chrome 中,以提供此功能以及其他一些功能。由于实施非常非常新,我在答案的底部提供了链接。
虽然 jsfiddle 的 iframe 结构完全阻止了拉动刷新,但我还在 Chrome Android 60.0.3112.116 上的平面 HTML 文档中测试了相同的脚本。
Full jsfiddle
event.preventDefault() 可以阻止浏览器默认行为,例如拉动刷新。大多数时候,我们想要通常的浏览器行为,而不是当它会导致下拉刷新时。由于在触摸向下移动屏幕并且我们滚动到文档顶部时会发生下拉刷新,因此我们只会在这种情况下调用preventDefault。
//We're going to make a closure that will handle events
//so as to prevent the pull-to-refresh behavior.
var pullToRefreshPreventer = (function() {
//To determine the direction in which a touch is moving,
//we hold on to a map from touch identifier to touches
//from the previous event.
var previousTouches = {};
return function(event) {
//First we get all touches in this event and set up
//the value which will replace `previousTouches`
//before this event handler exits.
var touches = Array.prototype.slice.call(event.touches);
nextTouches = {}
touches.forEach(function(touch){
nextTouches[touch.identifier] = touch;
});
//Pull-to-refresh behavior only happens if we are
//scrolled to the top of the document, so we can
//exit early if we are somewhere in the middle.
if(document.scrollingElement.scrollTop > 0) {
previousTouches = nextTouches;
return;
}
//Now we know that we are scrolled to the top of
//the document;
//look through the current set of touches and see
//if any of them have moved down the page.
for(var ix = 0; ix < touches.length; ix++) {
var touch = touches[ix],
id = touch.identifier;
//If this touch was captured in a previous event
//and it has moved downwards, we call preventDefault
//to prevent the pull-to-refresh behavior.
if(id in previousTouches && previousTouches[id].screenY < touch.screenY) {
event.preventDefault();
console.log("event.preventDefault() called")
break;
}
}
//lastly, we update previousTouches
previousTouches = nextTouches;
};
}());
//Since touch events which may call `preventDefault` can be
//much more expensive to handle, Chrome disallows such calls
//by default. We must add the options argument `{passive: false}`
//here to make it work.
document.body.addEventListener('touchmove', pullToRefreshPreventer, {passive: false});
document.body.addEventListener('touchend', pullToRefreshPreventer, {passive: false});
参考资料:
StackOverflow answer linking to chromestatus.com page
"Treat Document Level Touch Event Listeners as Passive", chromestatus
"Making touch scrolling fast by default"
"Touch events"
scroll-boundary-behavior链接:
chromestatus
chromium bug
github issue proposing the standard
draft css module,最后发布日期 2017-09-07