(一)前言
對於移動h5應用,會發現進場出現滑動橡皮筋效果,大部分情況下,如果將body設置爲滾動條情況下,只要設置html就fixed定位,其實就能解決這個問題,但是大部分產品,會使用局部定位的元素來實現滾動,那麼隨之問題就會發生。
(二)頁面元素滾動場景
本文解決方案,基本參考下面文章
參考鏈接
下面,我來說下,我遇到的問題場景
- 整體頁面未使用body作爲滾動條
- 內部定義div 爲listView 提供滾動容器
這種情況下,我遇到以下問題。
- 如果頁面有swiper,在swiper左右切換時候,頁面會因爲橡皮筋效果,出現頁面向下滾動問題,這種不管在h5站點,還是在ios保存爲桌面小程序的情況,都會出現。
- 頁面內部的listView會現在滑動到底部時候,出現上滑,觸動橡皮筋效果,導致滾動問題
(三)解決過程
首先,我直接的想法是禁用html的橡皮筋效果,但是我發現,listView在滾動到底部,依然會觸發,導致無法滾動,以至於給用戶一種滑動卡頓的效果。
然後,我測試了上文的overscroll-behavior屬性,但是發現,既然未解決我的問題,
最後,我考慮從js方面來解決這個問題,常規用法就是如下
window.addEventListener('touchmove', function (event) {
event.preventDefault()
}, false)
// Allows content to move on touch.
document.querySelector('.body-container').addEventListener('touchmove', function (event) {
event.stopPropagation()
}, false)
但是,我發現這種實現,鏈接作者提供相關的類庫,抱着嘗試的角度,我找到的他的倉庫。
iNoBounce
但是打開倉庫,你會發現,作者根本未提供npm的安裝方式,所以只要打開源碼,新建一個inobounce.ts的文件名,小小修改下作者的代碼
let startY = 0;
let enabled = false;
let supportsPassiveOption = false;
try {
const opts = Object.defineProperty({}, 'passive', {
get() {
supportsPassiveOption = true;
},
});
window.addEventListener('test', () => null, opts);
} catch (e) {
//
}
let handleTouchmove = (evt) => {
let el = evt.target;
const zoom = window.innerWidth / window.document.documentElement.clientWidth;
if (evt.touches.length > 1 || zoom !== 1) {
return;
}
while (el !== document.body && el !== document) {
const style = window.getComputedStyle(el);
if (!style) {
break;
}
if (el.nodeName === 'INPUT' && el.getAttribute('type') === 'range') {
return;
}
const scrolling = style.getPropertyValue('-webkit-overflow-scrolling');
const overflowY = style.getPropertyValue('overflow-y');
const height = parseInt(style.getPropertyValue('height'), 10);
const isScrollable = scrolling === 'touch' && (overflowY === 'auto' || overflowY === 'scroll');
const canScroll = el.scrollHeight > el.offsetHeight;
if (isScrollable && canScroll) {
const curY = evt.touches ? evt.touches[0].screenY : evt.screenY;
const isAtTop = startY <= curY && el.scrollTop === 0;
const isAtBottom = startY >= curY && el.scrollHeight - el.scrollTop === height;
if (isAtTop || isAtBottom) {
evt.preventDefault();
}
return;
}
el = el.parentNode;
}
evt.preventDefault();
};
const handleTouchstart = (evt) => {
startY = evt.touches ? evt.touches[0].screenY : evt.screenY;
};
const enable = () => {
window.addEventListener(
'touchstart',
handleTouchstart,
supportsPassiveOption ? { passive: false } : false,
);
window.addEventListener(
'touchmove',
handleTouchmove,
supportsPassiveOption ? { passive: false } : false,
);
enabled = true;
};
const disable = () => {
window.removeEventListener('touchstart', handleTouchstart, false);
window.removeEventListener('touchmove', handleTouchmove, false);
enabled = false;
};
const isEnabled = () => {
return enabled;
};
let testDiv = document.createElement('div');
document.documentElement.appendChild(testDiv);
// @ts-ignore
testDiv.style.WebkitOverflowScrolling = 'touch';
let scrollSupport =
'getComputedStyle' in window &&
window.getComputedStyle(testDiv)['-webkit-overflow-scrolling'] === 'touch';
document.documentElement.removeChild(testDiv);
if (scrollSupport) {
enable();
}
let iNoBounce = { enable, disable, isEnabled };
if (typeof module !== 'undefined' && module.exports) {
module.exports = iNoBounce;
}
然後,在你的react項目的根index,直接導入
import './utils/inobounce';
但是你需要注意一點,如果你自定義了滾動條 overflow-y: scroll這種 ,需要新增一個css屬性
-webkit-overflow-scrolling: touch;
當然 -webkit-overflow-scrolling還能爲長列表h5優化提供類似原生體驗,需要了解的朋友,可以去谷歌下。
到這裏,你可以打來你h5站點,發現大部分場景的橡皮筋效果已經得到解決,而且還不會影響listView的滾動效果。