这个插件给我最大的体会是,官网看不懂的,把官网的例子复制到自己项目中,然后修改成自己的代码,慢慢来就懂了。。。。
首先解释一下官网例1:自定义容器中各参数和方法的作用
MyBody():这个方法用于自定义滚动的范围。是整个body滚动?还是在你自定义的层里面滚动?(个人认为可以用css的相对定位,绝对定位,overflow来实现同样的效果,所以这个方法看喜好来。);
变量data:循环展示的数据集。(如果你的数据是从接口请求的数据,那么这个变量没什么用,与其关系对应的是请求的所有数据的拼接。比如请求一次:data就是这一次的数据集合;请求两次:data就是这两次请求数据的拼接集合);
变量NUM_SECTIONS:每一次加载更多显示几节。(视情况来,我的项目只是单纯的没有层级的列表,不需要这个);
变量NUM_ROWS_PER_SECTION:每一节显示多少行;
变量pageIndex :当前页码。
dataBlobs:所有数据的json集合。它这里json的key和value是一样的,格式为{'row1':row1,'row2':row2};
sectionIDs:所有节的index数组。(视情况来,我的项目只是单纯的没有层级的列表,不需要这个);
rowIDs:所有显示的行index数组;
genData():这个方法是生成DataSource中(cloneWithRowsAndSections, cloneWithRows)方法里面的参数,也就是(dataBlobs,sectionIDs,rowIDs)(如果你是接口请求的数据,绝大多数情况下不需要这个方法);
render中的const row变量:根据dataBlobs或者rowID这个二维数组的总长度来不停的循环data,直到循环完为止。简而言之,这个变量就是一个for循环;(如果是接口请求来的数据,应该循环接口返回数据的length);
if (index < 0) {
index = data.length - 1;
}
const obj = data[index--];
这时,这部分的data对应接口请求过来的总data拼接集合;
constructor,componentDidMount:照抄
// If you use redux, the data maybe at props, you need use `componentWillReceiveProps`:
这个注释部分在我的例子中会用到
onEndReached:底部加载更多的方法
---------------------------------------------------------------------------------------------------------------------------------------------------
以上我自己是懂的,但是写出来自己也有点看不太懂,但是已经非常尽量的在组织语言了。
下面附上我自己的代码图,如果有不懂或者需要附上redux部分代码的,欢迎评论,嘻嘻。
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { actionCreators } from './store';
import { ListView } from 'antd-mobile';
class StudentShare extends Component{
constructor(props) {
super(props);
const dataSource = new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2,
});
this.state = {
dataSource,
height: document.documentElement.clientHeight - (document.documentElement.clientWidth*74/375),
};
}
// If you use redux, the data maybe at props, you need use `componentWillReceiveProps`
componentWillReceiveProps(nextProps) {
if (nextProps.listDataArr.toJS() !== this.props.listDataArr.toJS()) {
// console.log(nextProps.listDataArr.toJS())
this.setState({
dataSource: this.state.dataSource.cloneWithRows(nextProps.listDataArr.toJS()),
});
}
}
componentDidMount(){
this.props.getAllList(this.props.listDataNone, 1, this.props.setPageSize);
}
render() {
const { fromPath, setPageSize, listType, pageIndex, listDataArr, isLoading, hasMore, onEndReached } = this.props;
let isNoList = listDataArr.toJS().length === 0 ? true : false;
let listLen = listDataArr.toJS().length;
let listDataObj = listDataArr.toJS();
let index = 0;
const row = (rowData, sectionID, rowID) => {
if (index > listLen) {
index = 0;
}
const obj = listDataObj[index++];
return (
<div key={rowID} className="item red">
<div className="imginfo">
<div className="label">倾情推荐</div>
</div>
<div className="rinfo">
<div className="title" dangerouslySetInnerHTML={{__html:obj.classTitle}}/>
<div className="desc" dangerouslySetInnerHTML={{__html:obj.introduce}}/>
<div className="comlabelgroup">
<span className="combblabel">名师分享</span>
<span className="comrrlabel">倾情推荐</span>
</div>
<div className="iconinfo clear">
{/*
<span className="fl icon_eye">2019</span>
<span className="fl icon_thumb">2019</span>
*/}
<span className="fr watch" onClick={ev => this.props.goVideo(obj.classId, this.props.history)}>立即观看</span>
</div>
<div className="price">免费</div>
</div>
</div>
);
};
return(
<div>
<div className="comlistpart m20b">
{isNoList ? (
<NoList/>
) : (
<div>
<ListView
ref={el => this.lv = el}
dataSource={this.state.dataSource}
renderFooter={() => (<div style={{ padding: 10, textAlign: 'center' }}>
{
hasMore ? (
isLoading ? 'Loading...' : 'Loaded'
) : '没有更多啦!'
}
</div>)}
renderRow={row}
style={{
height: this.state.height,
overflow: 'auto',
}}
pageSize={5}
// onScroll={() => { console.log('scroll'); }}
scrollRenderAheadDistance={500}
onEndReached={ev => onEndReached(pageIndex, setPageSize, hasMore, listDataArr)}
onEndReachedThreshold={10}
/>
</div>
)}
</div>
</div>
)
}
}
const mapStateToProps = (state) => {
return {
setPageSize: state.getIn(['kbstudent', 'setPageSize']),
pageIndex: state.getIn(['kbstudent', 'pageIndex']),
isLoading: state.getIn(['kbstudent', 'isLoading']),
hasMore: state.getIn(['kbstudent', 'hasMore']),
listData: state.getIn(['kbstudent', 'listData']),
listDataArr: state.getIn(['kbstudent', 'listDataArr']),
listDataNone: state.getIn(['kbstudent', 'listDataNone']),
}
}
const mapDispatchToProps = (dispatch) => {
return {
setFromPath(path){
dispatch(actionCreators.setFromPath(path));
},
getAllList(listDataArr, page, pagesize){
dispatch(actionCreators.getAllList(listDataArr, page, pagesize));
},
goVideo(pId, history){
let id = parseInt(pId);
history.push({ pathname:'/video/'+id,state:{formPath: '/studentshare'}});
},
onEndReached(page, setPageSize, hasMore, listDataArr) {
// load new data
// hasMore: from backend data, indicates whether it is the last page, here is false
if (!hasMore) {
return;
}
dispatch(actionCreators.changeLoading(true));
dispatch(actionCreators.changePage(page+1));
setTimeout(() => {
dispatch(actionCreators.getAllList(listDataArr, page+1, setPageSize));
}, 1000);
},
}
}
export default connect(mapStateToProps, mapDispatchToProps)(StudentShare);
注意点,listData是每一次请求的数据,listDataArr是多次请求的数据集合,listDataNone是空数组
踩坑,我用了immutable。之前,componentWillReceiveProps这个方法的数据没有用toJS方法,页面一直有重复数据,所以,用了immutable就一定要用toJS来转化下数据,!!!!!!!强调。
redux部分-reducer
import { fromJS } from 'immutable';
import * as constants from './constants';
const defaultState = fromJS({
fromPath: '/',
listData: [],
listDataArr: [],
listDataNone: [],
listType: 2,
pageIndex: 1,
setPageSize: 10,
isLoading: false,
hasMore: true,
})
export default ( state = defaultState, action ) => {
switch(action.type) {
case constants.SET_FROMPATH:
return state.set('fromPath', action.value);
case constants.CHANGE_ALL_LIST:
return state.merge({
'listData': fromJS(action.data),
'listDataArr': fromJS(action.plist),
});
case constants.CHANGE_LOADING:
return state.set('isLoading', action.isShow);
case constants.CHANGE_PAGE:
return state.set('pageIndex', action.value);
case constants.CHANGE_HASMORE:
return state.set('hasMore', action.isShow);
default:
return state;
}
}
redux部分-constants
export const SET_FROMPATH = 'kbstudent/SET_FROMPATH';
export const CHANGE_ALL_LIST = 'kbstudent/CHANGE_ALL_LIST';
export const CHANGE_LOADING = 'kbstudent/CHANGE_LOADING';
export const CHANGE_PAGE = 'kbstudent/CHANGE_PAGE';
export const CHANGE_HASMORE = 'kbstudent/CHANGE_HASMORE';
redux部分-actionCreators
import * as constants from './constants';
import abbr from '../../../../config/abbr';
import { apiGetFameShare } from '../../../../config/index';
export const getAllList = (list, pflag, ptype, ppage, ppagesize) => {
let flag = parseInt(pflag);
let type = parseInt(ptype);
let page = parseInt(ppage);
let pagesize = parseInt(ppagesize);
let formData = {
flag: flag,
type: type,
page: page,
pagesize: pagesize,
}
return (dispatch) => {
//获取全部热门课程
apiGetFameShare(formData).then(response => {
if (response.code === abbr.okId) {
let plist = list.toJS().concat(response.data);
if(plist.length >= response.total){
dispatch(changeHasmore(false));
}
dispatch(changeAllList(response.data, plist));
dispatch(changeLoading(false));
}else{
dispatch(changeAllList([],[]));
dispatch(changeLoading(false));
dispatch(changeHasmore(false));
return;
}
}).catch(error => {
dispatch(changeAllList([],[]));
dispatch(changeLoading(false));
dispatch(changeHasmore(false));
console.log(error)
})
}
}
export const changeAllList = (data, plist) => ({
type: constants.CHANGE_ALL_LIST,
data, plist
})
export const changeLoading = (isShow) => ({
type: constants.CHANGE_LOADING,
isShow
})
export const changePage = (value) => ({
type: constants.CHANGE_PAGE,
value
})
export const changeHasmore = (isShow) => ({
type: constants.CHANGE_HASMORE,
isShow
})
export const setFromPath = (value) => ({
type: constants.SET_FROMPATH,
value
})