在React中引入IScroll插件做滾動


最近做一個H5項目,數據交互量比較大,很多頁面都是從后台拿過來數據做一個列表顯示,這自然就遇到了滾動。

剛開始我直接使用css做法,直接添加overflow: scroll;但在微信端用戶滑動會直接將整個頁面拖動,露出頂部的域名和底部的黑色背景。用戶反映體驗不好,要改……好吧,自己動手。但這並不是好改的,因為在React中都是構建的是虛擬DOM,直接操作DOM也會對性能有一定影響。這時候網上搜了一下,拿出一個解決方案,獻出部分代碼:

  

import React from 'react';
import { render } from 'react-dom';
import Router from './app/router';
import '../common/css/base.styl';
import '../common/css/waaStyle.styl';
import '../common/css/page.styl';
var divDom = document.createElement('div');
divDom.setAttribute('id', 'wrap');

document.body.appendChild(divDom);
document.body.addEventListener("touchmove",function (e) {
    e.preventDefault();
},false);
render(<Router />, divDom);

這是在React的根頁面下直接禁用touchmove事件,禁止用戶touchmove,可以達到不出現域名和黑色邊框的效果。

由於禁止touchmove事件,在需要列表滾動的地方,overflow:scroll;監聽不到touchmove了,滑動變得無效,怎么解決呢?我們可以在需要滾動的地方禁止冒泡事件:

//首先要獲取需要禁止冒泡事件的dom,由於React是構建虛擬的dom,可以這樣拿到dom:ref= {(ref) => {this.dom = ref}};

componentDidMount () {
      this.dom.addEventListener("touchmove",function (e) {
        e.stopPropagation();
      },false);  
} 

//dom在頁面掛載完成后,禁止冒泡事件。   

  加上這樣的代碼后,就會發現,整個頁面仍然是禁止滑動,列表頁可以正常滾動,但是,當列表滾動到底的時候,用戶繼續滑動,整個頁面仍然會跟着滑動,又露出我們不想看到的部分,感覺好氣呀……

冷靜分析一下,這條路是走不通的,由於列表區域禁止了冒泡事件,那么用戶只要在列表區域滑動,那么你在body上做的禁止滑動就是沒有效果的!

  萬般無奈下,我有搬來了我的老伙計:IScroll.js。之所以選他,因為他有一個非常有用的方法:refresh();我只要在componentDidMount中實例化Iscroll,並且在React數據更新后再次refresh就可以了。那么開始做了。

React框架中引入我們想要的插件,只要這樣做就行:

import Iscroll from "moudle/iscroll/Iscroll";

然后頁面掛載完成后我們進行實例化

componentDidMount() {
  setTimout(function () {//由於手機性能的原因,我們在定時器里面進行實例化
    this.myIScroll = new IScroll("#dom",{
    mouseWheel: true,
    bounce: true,
    scrollbars: false,
});  
  },10);
}

一但React檢測到數據有更新,他就會自動刷新頁面,那么我們這個時候需要重新刷新IScroll:

componentDidUpdate() {
  this.myIScroll.refresh();  
}

代碼做到這里,我們就會發現,即使禁止touchmove事件,我們依然可以使用滾動列表,問題完美解決!不過,此時客戶大手一揮,指着我們的滾動條,這個滾動條有點丑呀,能不能把它做得科技感一些……哎,數不清的星星,改不完的需求啊,不過,這個對於我們無(xia)所(chui)不(niu)能(bi)的程序猿也是可以做得。在IScroll中,它的滾動條是由兩個做了定位的div構成的,那么

我們在實例化IScroll的時候參數中設置:

this.myIScroll = new IScroll("#dom",{
scrollbars: 'custom',//即scrollbars的值設置成字符串:“custom”即可
});

然后我們在樣式表中使用兩個類名:

.iScrollIndicator和.iScrollVerticalScrollbar.iScrollLoneScrollbar寫入樣式,這樣組成滾動條的兩個div就可以長成我們希望的樣子啦!
但是根據需求,有的列表很長,需要分頁加載,那么就需要判斷用戶拖動后是否需要加載下一頁的數據了。
基本的思路是,利用this.y得到向上移動的距離,用里面框的高度減去移動的距離,再減去外面框的高度,如果小於某一個高度,我們去請求數據,之后重新渲染就行了。但是,我查閱了IScroll的相關代碼,文檔上並沒有寫出內外兩個框高度的接口,也曾經試着自己在源碼里添加獲得框高度的方法,但是在實例化后獲取這個值總會有各種各樣的問題。最后經過仔細研究IScroll源碼,發現外面框的高度就是實例化后的:this.wrapperHeight,而里面框的高度就是:this.scrollerHeight,這樣我們減去this.y的絕對值后,就可以判斷出是否需要加載新的數據了。給大爺們線上代碼:
componentDidMount () {
        var self = this;
        const options = {
            preventDefault: false,
            zoom: false,
            mouseWheel: true,
            probeType: 3,
            bounce: true,
            scrollbars: true,
        };
        this.iScrollInstance = new IScroll(this.scrollContent,options);
        this.iScrollInstance.on('scrollEnd', function() {

            var shouldGet = this.scrollerHeight + this.y - this.wrapperHeight;//注意this.y一定是非正數,所以這里是加啦!

            if (shouldGet < 200 && this.directionY === 1 && !self.state.loading) { //我這里設置的臨界值是200,即列表滾動結束后,如果里框的高度還有小於200px的內容沒有顯示過就會去加載新的數據。
                if(self.state.pageNo >= self.state.totalPage) {
                    Action.update({noMore: true});

                } else {
                    self.state.pageNo ++;
                    Action.getList({pageNo: self.state.pageNo});
                }
            }
        });
    }

做到這里,我們利用IScroll想解決的需求都可以滿足了……







免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM