React-實現上拉加載更多

1. 寫在前面

我最開始糾結當用戶滑動時onTouchMove事件會不停的執行去調接口,因而我僥倖的想只用onTouchEnd事件去判
斷用戶是否滑到最底部,可是這種方法應用到項目中才發現點擊的時候也會觸發onTouchEnd,實際應用並不理想。
光判斷滑到最底部是不夠的,首先須要知道用戶如今的操做,是點擊仍是滑動(向上、向下、向左、向右),這裏
受到了[原生js判斷手指滑動方向][1]的啓發。

2. demo

class demo Component {
     constructor(props) {
        super(props);
        this.state = {
            finished: false,//是否所有加載完畢
            isFoot: true,   //阻止用戶頻繁上拉調接口
        }
        this._page = 1;              //分頁頁碼                           
        this.val = '';               //搜索框的值
        this._page_size = 5;         //每頁顯示個數 
        this.startx;                 //觸摸起始點x軸座標
        this.starty;                 //觸摸起始點y軸座標 
    }
    //接觸屏幕
    touchStart(e) {
        this.startx = e.touches[0].pageX;
        this.starty = e.touches[0].pageY;
    }
    //離開屏幕([e.changedTouches][2])
    touchEnd(e) {
        let endx, endy;
        endx = e.changedTouches[0].pageX;
        endy = e.changedTouches[0].pageY;
        let direction = this.getDirection(this.startx, this.starty, endx, endy);
        switch (direction) {
            case 0:
                console.log("未滑動!");
                break;
            case 1:
                console.log("向上!");
                this.loadData();
                break;
            case 2:
                console.log("向下!");
                break;
            case 3:
                console.log("向左!");
                break;
            case 4:
                console.log("向右!");
                break;
            default:
        }
    }
    //觸摸點和離開點連線與[x軸角度][3]
    getAngle(angx,angy) {
        return Math.atan2(angy, angx) * 180 / Math.PI;
    }
    //根據接觸和離開判斷方向 1向上 2向下 3向左 4向右 0未發生滑動([Math.abs][4])
    getDirection(startx, starty, endx, endy) {
        let angx = endx - startx;
        let angy = endy - starty;
        let result = 0;

         //若是滑動距離過短
         if (Math.abs(angx) < 2 && Math.abs(angy) < 2) {
            return result;
        }
        let angle = this.getAngle(angx, angy);
        if (angle >= -135 && angle <= -45) {
            result = 1;
        } else if (angle > 45 && angle < 135) {
            result = 2;
        } else if ((angle >= 135 && angle <= 180) || (angle >= -180 && angle < -135)) {
            result = 3;
        } else if (angle >= -45 && angle <= 45) {
            result = 4;
        }
 
        return result;
    }
    //**向上滑動時(在這裏才真正的判斷是否到最底部)**
    loadData() {
        console.log("數據的高-------------------------", this.refs.onPullUp.clientHeight);
        console.log("滾動的高------------------------", document.documentElement.scrollTop);
        console.log("滾動的高------------------------", document.body.scrollTop);
        console.log("屏幕的高------------------------", document.documentElement.clientHeight);
        let { meActs } = this.props;
        let dataHeight = this.refs.onPullUp.clientHeight;
        let scrollHeight = document.body.scrollTop || document.documentElement.scrollTop;
        let screenHeight = document.documentElement.clientHeight;
        const h = 10;//自定義距離底部多少時concat數據
        if (dataHeight - scrollHeight - h < screenHeight && this.state.isFoot) {
            this.setState({
                isFoot: false,
            });
            console.log("應該只顯示1次");
            let params = {
                value: this.val,
                page_index: this._page,
                page_size: this._page_size,
            }
            meActs.getRecentReadList(this.accessKey, this.accessID, params).then((res) => {
                if (res.data.code === 10000 && res.data.data.list.length > 0) {
                    this.setState({
                        isFoot: true,
                    });
                    this._page++;
                }
                //數據加載完畢
                if (res.data.code === 10000 && res.data.data.list.length == 0) {
                    this.setState({
                        finished: true,
                    })
                }
            });
        }
    }
    
    render() {
        return(
             <div className='recentRead paddingTop90' ref="onPullUp">
                <TitleBar title="歷史閱讀" onClickBack={this.onClickBack.bind(this)} />
                <SearchBar
                    onSubmit={this.onSearch.bind(this)}
                    onCancel={this.onSearchCancel.bind(this)}
                    placeholder='搜索'
                    ref="searchBar"
                />
                <div className="touch-box" onTouchStart={this.touchStart.bind(this)} onTouchEnd={this.touchEnd.bind(this)}>
                    {listItems}
                </div>
                <div className="common-bottomTotal">
                    {
                        this.state.finished ? <span>我是有底線的</span> :
                            recentReadList.list.length > 0 ? this.state.isFoot ? <span >上拉加載更多</span> : <ActivityIndicator text="請稍等..." /> :
                                <span className='iconfont icon-taidu2'>暫無信息</span>
                    }
                </div>
            </div>
        )
    }
}

3. 兼容性

微信端ios 安卓暫時還未發現任何異常(已上線的項目)

4. 結語

移動端觸摸事件的用處遠不止如此,此次是由於antd自帶的上拉加載插件在自身項目中應用太複雜因此決定本身
寫一個知足自身項目需求的代碼少兼容性還看得過去的就行。最近想找react圖片縮放的插件,感受也跟觸摸事件
有關,能夠研究一下。

**react

相關文章
相關標籤/搜索