近期項目改版,對原有的h5頁面進行了從新設計,數據呈現變成了瀑布流。但願新版兼容ios和安卓兩端的狀況下,無限制的刷新加載數據。大體效果以下:css
整個頁面分4部分:html
指望效果:列表滾動到用戶信息卡片消失後,展現另外一個吸頂的導航欄。react
效果以下:
分析能夠發現,首先咱們要作的就是適配iPhone X,其次咱們須要監聽列表的滾動高度,在pc和安卓上監聽滾動事件是沒有問題的,可是ios上滾動過程當中不會觸發scroll事件,而是滾動結束後會觸發onscrollend事件,這就不能知足實時監聽高度的要求。通過簡單調研,決定站在巨人的肩膀上,經過iscroll、better-scroll等js庫實現。這兩個庫都是解決各類滾動兼容的js庫,不少常見的輪播、picker組件都是基於這些庫封裝的。順便說一句,還有個庫也不錯(simulation-scroll-y)ios
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); }
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函數,使用起來無比順滑。
和大多數滾動處理同樣,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));
感受寫得好亂,作事情和寫文章果真是兩回事。。。
有興趣能夠訪問:https://3hours.taobao.com/new...一塊兒來作公益吧!