React-實現上拉載入更多
阿新 • • 發佈:2019-02-01
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圖片縮放的外掛,感覺也跟觸控事件
有關,可以研究一下。
**