一次react滾動列表的實踐---兼容ios安卓

1、背景

近期項目改版,對原有的h5頁面進行了從新設計,數據呈現變成了瀑布流。但願新版兼容ios和安卓兩端的狀況下,無限制的刷新加載數據。大體效果以下:css

圖片描述

整個頁面分4部分:html

  • 頂部導航
  • 步數狀態卡片
  • 用戶信息卡片
  • 滾動列表

指望效果:列表滾動到用戶信息卡片消失後,展現另外一個吸頂的導航欄。react

效果以下:
圖片描述
分析能夠發現,首先咱們要作的就是適配iPhone X,其次咱們須要監聽列表的滾動高度,在pc和安卓上監聽滾動事件是沒有問題的,可是ios上滾動過程當中不會觸發scroll事件,而是滾動結束後會觸發onscrollend事件,這就不能知足實時監聽高度的要求。通過簡單調研,決定站在巨人的肩膀上,經過iscrollbetter-scroll等js庫實現。這兩個庫都是解決各類滾動兼容的js庫,不少常見的輪播、picker組件都是基於這些庫封裝的。順便說一句,還有個庫也不錯(simulation-scroll-yios

2、進入正題

  • 1.適配iPhone X

PhoneX的適配,在iOS 11中採用了viewport-fit的meta標籤做爲適配方案;viewport-fit的默認值是auto。react app的渲染內容都在id爲root的 div裏面。咱們給這個div加上iphoneX的safe-area-inset屬性便可。更多相關內容,這篇文章寫的挺詳細git

<meta name='viewport' content='width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover' />
#root{
    height:100vh;
    padding-top: constant(safe-area-inset-top);
    padding-left: constant(safe-area-inset-left);
    padding-right: constant(safe-area-inset-right);
    padding-bottom: constant(safe-area-inset-bottom);
    padding-top: env(safe-area-inset-top);
    padding-left: env(safe-area-inset-left);
    padding-right: env(safe-area-inset-right);
    padding-bottom: env(safe-area-inset-bottom);
  }
  1. 2.頁面github

    頁面結構很少說,比較基礎。
    div.container-> div#wrapper->div.list->div.list-item
    值得注意的是,wrapper須要設置絕對定位。同時,經過transform: translateZ(0);開啓硬件加速,瀏覽器在渲染時會經過GPU進行渲染。有效緩解安卓端滾動卡頓的問題,相似的css還有很多,css硬件加速不要濫用,不然會致使不應使用gpu的layer使用gpu,佔用內存太高,致使頁面卡頓,甚至黑屏,通常狀況下,給不一樣的硬件加速元素添加一個不一樣的z-index屬性能夠解決。-webkit-overflow-scrolling: touch使ios滾動順滑。
    // 初始化BScroll僞代碼,生產慎用:web

    import BScroll from 'better-scroll';
      
    this.myScroll = new BScroll('#wrapper', {
                  mouseWheel : true,
                  // 無需scrollbar
                  scrollbar  : false,
                  // propType屬性設置爲3在慣性動畫期間也觸發onscroll事件
                  probeType  : 3,
                  // 容許滾動列表內可點擊、touch
                  click      : true,
                  tap        : true,
                  // 上拉加載,正值自動觸發加載
                  pullUpLoad : {
                      threshold: 50
                  }
              });

一開始,我將better-scroll初始化代碼放在container組件的componentDidMount函數中,但因爲初始數據也在這個函數獲取,致使當返回較慢的時候初始化的#wrapper沒有內容,此時須要手動點擊加載更多才展示數據,不符合預期。因此考慮將初始化代碼放到list組件渲染完成以後的componentDidUpdate函數中。list組件渲染完成後,就能夠初始化咱們的滾動類,這裏使用的better-scroll,iscroll使用相似。具體參考上面連接。瀏覽器

#wrapper {
        position:absolute;
        top:0;
        left:0;
        width:100vw;
        overflow:auto;
        height: 100vh;
        transform: translateZ(0);
        z-index: 33;
        -webkit-overflow-scrolling: touch
    }

具體的,能夠將初始化代碼放在list組建的container組件的handleScrollRefresh函數。這個函數做爲props傳到list組件,在list組件的componentDidUpdate鉤子裏面執行:
container組件:app

handleScrollRefresh () {
      if (this.myScroll) {
          this.myScroll.refresh();
          console.log('refreshed ');
      } else {
          console.log('initialized');
          this.myScroll = new BScroll('#wrapper', {
              ...//初始化參數
          });
          this.myScroll.on('scroll',this.handleScroll, 10);
          this.myScroll.on('pullingUp', this.loadMore);
      }
  }

list 組件:iphone

componentDidUpdate () {
      if (this.props.onRefresh) {
          this.props.onRefresh();
      }
  }

網上不少滾動卡頓的狀況,大都是加載數據後沒有執行refresh致使的。同時,加載數據成功後咱們須要調用scroll的finishPullUp方法。下次上拉才能繼續加載數據。這樣,每當加載新的數據後,list組件就會執行componentDidUpdate,此時就調用了scroll的finishPullUp、refresh函數,使用起來無比順滑。

3、優化

  1. 和大多數滾動處理同樣,better-scroll的scroll事件也會頻繁觸發,這對性能仍是有必定影響的,畢竟咱們不須要過於頻繁的執行回調函數。

    throttle (func, delay) {
      let lastTime = null;
      return function () {
          let context = this;
          let args = arguments;
          let now = new Date().getTime();
          if (!lastTime || (now - lastTime) > delay) {
              lastTime = now;
              func.apply(context, args);
          }
      };
    };

    不想寫直接使用lodash也能夠:

    //不精準的每秒十次
    this.myScroll.on('scroll', this.throttle(this.handleScroll, 100));
  2. 函數綁定,不傳參的狀況下在constructor中綁定this。而不是在render中使用this.xxx.bind(this)。
  3. list 圖片大小限制,本次因爲部分列表item圖片過大,在安卓上致使黑屏的問題出現。排查了好久才發現這個問題。經過在圖片url拼接參數限制大小解決了這個問題。

最後

感受寫得好亂,作事情和寫文章果真是兩回事。。。
有興趣能夠訪問:https://3hours.taobao.com/new...一塊兒來作公益吧!

相關文章
相關標籤/搜索