初用Ant Design Mobile 中 ListView ,看到官方示例,新手朋友估計第一反應都是一臉蒙逼,現在我們寫一個最簡單的示例,除了讓代碼運作起來,也讓大家知道每一行代碼的作用
"dependencies": { "antd": "^3.26.11", "antd-mobile": "^2.3.1", "axios": "^0.19.2", "qs": "^6.9.1", "react": "^16.6.3", "react-dom": "^16.6.3", "react-redux": "^6.0.0", "react-router-dom": "^4.3.1", "redux": "^4.0.5" }
直接上代碼示例,基本只要把請求方法換一下,就能直接用,對於關鍵代碼都有注釋,個人覺得比官網示例更簡單易上手
import React, { Component } from 'react' import { NavBar, Icon, ListView, PullToRefresh, Toast } from 'antd-mobile' import Api from '@/api/index.js' class myCourse extends Component { constructor(props) { super(props) // 創建ListViewDataSource對象 const dataSource = new ListView.DataSource({ rowHasChanged: (row1, row2) => row1 !== row2 // rowHasChanged(prevRowData, nextRowData); 用其進行數據變更的比較 }) this.state = { dataSource, datas: [], pageNo: 1, pageSize: 2, hasMore: true, refreshing: true, isLoading: true, dataArr: [], } } componentDidMount() { this.getData(true) } getData(ref = false) { //獲取數據 var para = {} para.pageSize = this.state.pageSize para.pageNo = this.state.pageNo Api.get('http://www.xxx.com/api/myCourse', para, res => { const dataList = res.data.list const len = dataList.length if (len <= 0) { // 判斷是否已經沒有數據了 this.setState({ refreshing: false, isLoading: false, hasMore: false }) Toast.info('沒有數據了~', 1) return false } if (ref) { //這里表示刷新使用 // 下拉刷新的情況,重新添加數據即可(這里等於只直接用了第一頁的數據) this.setState({ pageNo: this.state.pageNo, dataSource: this.state.dataSource.cloneWithRows(dataList), // 數據源中的數據本身是不可修改的,要更新datasource中的數據,請(每次都重新)調用cloneWithRows方法 hasMore: true, // 下拉刷新后,重新允許開下拉加載 refreshing: false, // 是否在刷新數據 isLoading: false, // 是否在加載中 dataArr: dataList // 保存數據進state,在下拉加載時需要使用已有數據 }) } else { // 這里表示上拉加載更多 // 合並state中已有的數據和新增的數據 var dataArr = this.state.dataArr.concat(dataList) //關鍵代碼 this.setState({ pageNo: this.state.pageNo, dataSource: this.state.dataSource.cloneWithRows(dataArr), // 數據源中的數據本身是不可修改的,要更新datasource中的數據,請(每次都重新)調用cloneWithRows方法 refreshing: false, isLoading: false, dataArr: dataArr // 保存新數據進state }) } }) } // 下拉刷新 onRefresh = () => { this.setState({ refreshing: true, isLoading: true, pageNo: 1 // 刷新嘛,一般加載第一頁,或者按你自己的邏輯(比如每次刷新,換一個隨機頁碼) }, ()=>{ this.getData(true) }) } // 滑動到底部時加載更多 onEndReached = (event) => { // 加載中或沒有數據了都不再加載 if (this.state.isLoading || !this.state.hasMore) { return } this.setState({ isLoading: true, pageNo: this.state.pageNo + 1, // 加載下一頁 }, ()=> { this.getData(false) }) } render() { const row = (rowData, sectionID, rowID) => { // 這里rowData,就是上面方法cloneWithRows的數組遍歷的單條數據了,直接用就行 return ( <div key={rowID} className="article"> <div className="article-title"> {rowData.courseTitle} </div> <div className="article-body"> <div className="hidden">id: {rowData.id}</div> <div ><label className="label-3em">姓名</label>:{ rowData.userName }</div> </div> </div> ) } return ( <div className="content-bg"> <div className="content-box"> <ListView ref={el => this.lv = el} dataSource={this.state.dataSource} renderHeader={() => (<NavBar mode="light" icon={<Icon type="left" />} onLeftClick={() => this.props.history.push('/usercenter') } >我的課程</NavBar>)} renderFooter={() => (<div className="footer">{this.state.isLoading ? '加載中...' : '暫無更多數據'}</div>)} renderRow={row} useBodyScroll pullToRefresh={<PullToRefresh refreshing={this.state.refreshing} onRefresh={this.onRefresh} />} onEndReachedThreshold={10} onEndReached={this.onEndReached} pageSize={5} /> </div> </div> ); } } export default myCourse
如果不使用下拉刷新,那代碼就更少了,關鍵代碼就是要合並新增數據和之前加載的數據,concat方法即可
var dataArr = this.state.dataArr.concat(dataList)
然后就是更新到dataSource中,需要用cloneWithRows方法,這點可以參考官方文檔的解釋,這里的官方文檔不是antd文檔, 是React Native https://reactnative.cn/docs/0.45/listviewdatasource.html 關於 ListView.DataSource的介紹,讀懂的這個,再用Antd ListView就好理解多了
import React, { Component } from 'react' import { NavBar, Icon, ListView, PullToRefresh, Toast } from 'antd-mobile' import Api from '@/api/index.js' class myCourse extends Component { constructor(props) { super(props) // 創建ListViewDataSource對象 const dataSource = new ListView.DataSource({ rowHasChanged: (row1, row2) => row1 !== row2 // rowHasChanged(prevRowData, nextRowData); 用其進行數據變更的比較 }) this.state = { dataSource, datas: [], pageNo: 1, pageSize: 2, hasMore: true, refreshing: true, isLoading: true, dataArr: [], } } componentDidMount() { this.getData(true) } getData(ref = false) { //獲取數據 var para = {} para.pageSize = this.state.pageSize para.pageNo = this.state.pageNo Api.get('http://www.xxx.com/api/myCourse', para, res => { const dataList = res.data.list const len = dataList.length if (len <= 0) { // 判斷是否已經沒有數據了 this.setState({ refreshing: false, isLoading: false, hasMore: false }) Toast.info('沒有數據了~', 1) return false } // 這里表示上拉加載更多 // 合並state中已有的數據和新增的數據 var dataArr = this.state.dataArr.concat(dataList) //關鍵代碼 this.setState({ pageNo: this.state.pageNo, dataSource: this.state.dataSource.cloneWithRows(dataArr), // 數據源中的數據本身是不可修改的,要更新datasource中的數據,請(每次都重新)調用cloneWithRows方法 refreshing: false, isLoading: false, dataArr: dataArr // 保存新數據進state }) }) } // 滑動到底部時加載更多 onEndReached = (event) => { // 加載中或沒有數據了都不再加載 if (this.state.isLoading || !this.state.hasMore) { return } this.setState({ isLoading: true, pageNo: this.state.pageNo + 1, // 加載下一頁 }, ()=> { this.getData(false) }) } render() { const row = (rowData, sectionID, rowID) => { // 這里rowData,就是上面方法cloneWithRows的數組遍歷的單條數據了,直接用就行 return ( <div key={rowID} className="article"> <div className="article-title"> {rowData.courseTitle} </div> <div className="article-body"> <div className="hidden">id: {rowData.id}</div> <div ><label className="label-3em">姓名</label>:{ rowData.userName }</div> </div> </div> ) } return ( <div className="content-bg"> <div className="content-box"> <ListView ref={el => this.lv = el} dataSource={this.state.dataSource} renderHeader={() => (<NavBar mode="light" icon={<Icon type="left" />} onLeftClick={() => this.props.history.push('/usercenter') } >我的課程</NavBar>)} renderFooter={() => (<div className="footer">{this.state.isLoading ? '加載中...' : '暫無更多數據'}</div>)} renderRow={row} useBodyScroll onEndReachedThreshold={10} onEndReached={this.onEndReached} pageSize={5} /> </div> </div> ); } } export default myCourse