react 資料懶載入-滾動實現

NO IMAGE

使用場景

專案中碰到這樣一種情況,後臺介面資料由於太多沒法一次傳輸,因此希望前端在調介面時設定pageIdx和pageSize欄位實現懶載入。前端頁面上邊一部分為選項欄下面一部分為滾動區域,大致的html結構簡單抽象如下:

<div className='wrapper'>
<div className='header'></div>
<div className='scroll-body'></div>
</div>

簡單的上下佈局,外層為wrapper封裝類,裡面分上下兩層,上面header類固定,下面就是要實現滾動懶載入的scroll-body區域。

涉及的問題列表:

  1. 如何計算scroll-body區域的高度來讓scroll區域填充完除了header外的剩餘部分,採用的css為:
.scroll-body {
overflow: auto; //設定scroll overflow
-webkit-overflow-scrolling: touch; // 優化移動端滑動體驗
}
  1. 如何判斷頁面滾動到底部?

解決方案

  1. 針對第一個問題,可行的辦法有兩個:

方案1

在componentDidMount後獲取對應header的高度,然後用window.innerHeight減去渲染後的header ref高度,公式如下:

scrollHeight = window.innerHeight – this.header.clientHeight

在render方法中需要給header提前設定ref,並且需要新增一個state來控制,具體程式碼如下:

class Test extents Component{
constructor(props){
super(props);
this.state = {
scrollHeight: 0
}
}
componentDidMount(){
this.setState({
scrollHeight: window.innerHeight - this.header.clientHeight
})
}
render(){
const {scrollHeight} = this.state;
return (
<div className='wrapper'>
<div className='header' ref={ref=>this.header}></div>
<div className='scroll-body' style={{height: scrollHeight}}></div>
</div>
)
}
}

上述方案的優點是可以動態設定高度,減少響應的計算,缺點是必須在render渲染後才能設定。

方案2

提前計算高度,這裡有個限制,比如現在移動端中設定header的高度為2rem,需要從rem轉換到畫素,而獲取當前裝置的html的fontSize的方法可用的還比較有限,比如document.documentElement.style.fontSize,返回的數值為字串比如’165px’,還沒法直接拿來用,如果沒有設定的話返回的是空串”。需要做個處理,具體依據專案中而定。


  1. 如果判斷滾動到底部,觸發介面調取下一頁的資料?
    react有不少現成的實現滾動的元件,在google上搜尋會出來很多。不過就實現來說也是比較簡單的,這裡給出一種可行的方案:
class Test extents Component{
constructor(props){
super(props);
this.state = {
scrollHeight: 0,
hasMore: true,// 判斷介面是否還有資料,通過介面設定
dataList:[], // 資料列表
}
}
componentDidMount(){
this.setState({
scrollHeight: window.innerHeight - this.header.clientHeight
})
}
// 處理滾動監聽
handleScroll(){
const {hasMore} = this.state;
if(!hasMore){
return;
}
//下面是判斷頁面滾動到底部的邏輯
if(this.scrollDom.scrollTop   this.scrollDom.clientHeight >= this.scrollDom.scrollHeight){
this.fetchData()
}
}
fetchData(){
// 介面呼叫資料欄位
//傳入的引數包括但不限於:pageIndex, pageSize。。。
// 獲取後更新的資料包括但不限於:dataList,hasMore。。。
}
render(){
const {scrollHeight} = this.state;
return (
<div className='wrapper'>
<div className='header' ref={ref=>this.header}></div>
<div
ref={body=>this.scrollDom = body} 
className='scroll-body' 
style={{height: scrollHeight}}
onScroll={this.handleScroll.bind(this)}
>
</div>
</div>
)
}
}