談談移動端IOS橡皮筋特效

(一)前言
對於移動h5應用,會發現進場出現滑動橡皮筋效果,大部分情況下,如果將body設置爲滾動條情況下,只要設置html就fixed定位,其實就能解決這個問題,但是大部分產品,會使用局部定位的元素來實現滾動,那麼隨之問題就會發生。

(二)頁面元素滾動場景
本文解決方案,基本參考下面文章
參考鏈接

下面,我來說下,我遇到的問題場景

  1. 整體頁面未使用body作爲滾動條
  2. 內部定義div 爲listView 提供滾動容器

這種情況下,我遇到以下問題。

  1. 如果頁面有swiper,在swiper左右切換時候,頁面會因爲橡皮筋效果,出現頁面向下滾動問題,這種不管在h5站點,還是在ios保存爲桌面小程序的情況,都會出現。
  2. 頁面內部的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的滾動效果。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章