一、什么是ListView
ListView组件是antd-mobile中的列表展示组件,适用于显示同类的长列表数据类型,对渲染性能有一定的优化效果。官网地址: https://mobile.ant.design/components/list-view-cn/.在开发前端页面中,无论是手机端还是PC端都经常需要用到列表页展示(如下图点餐列表)。
图1
一般情况下我会把数据都聚合成数组或者对象,然后通过遍历数据集合把要展示的信息逐条渲染出来。如果仅仅从展示效果角度来说,这种方法是可以实现的。但是当需要的功能比较复杂的时候,比如你想控制初始渲染多少行数据、每次事件循环(每帧)渲染的行数、当列表滑动到某一位置时位置触发某一个事件等,原始的方法实现起来就十分的麻烦,而antd-mobile中的ListView组件实现起来就非常的方便。但是官网上对ListView组件的用法写的不详细,网上相关的资料也比较少。最近项目开发中需要用到这个组件,踩了一些坑,这里总结一下需要注意的几个点。
二、ListView如何渲染数据
渲染下面这个列表图2
图3
代码 <br>
import React, {Component}from 'react';
import {ListView} from 'antd-mobile'
export default class Test extends Component {
constructor(props:any){
super(props);
this.state={
list: new ListView.DataSource({
rowHasChanged :(row1: any, row2: any)=>{
console.log('row1', row1);
console.log('row2', row2);
return row1!== row2;
}
}),
firstArr:['苹果','栗子','橘子','桃子','葡萄','葡萄'],
secondArr:['娃哈哈','健力宝','栗子','青岛','二锅头'],
}
}
componentDidMount(){
this.setState({
list:this.state.list.cloneWithRows({...this.state.firstArr})
},()=>{console.log(this.state.list)})
}
toggle = (kind) =>{
console.log('kind',kind)
if(kind=='fruit'){
this.setState({
list:this.state.list.cloneWithRows({...this.state.firstArr})
},()=>{console.log(this.state.list)})
};
if(kind=='drink'){
this.setState({
list:this.state.list.cloneWithRows({...this.state.secondArr})
},()=>{console.log(this.state.list)})
};
}
render(){
const row=(rowData, sectionID, rowID) => {
console.log('rowData', rowData);
console.log('sectionID', sectionID);
console.log('rowID', rowID);
return(
<ul key={rowID}>
<li>{rowData}</li>
</ul>
)
}
return (
<div>
<button onClick={this.toggle.bind(this,'fruit')}>水果</button>
<button onClick={this.toggle.bind(this,'drink')}>饮料</button>
<div>
<ListView
ref={el => this.lv = el}
dataSource={this.state.list}
renderHeader={() => <span>header</span>}
renderRow={row}
useBodyScroll={true}
pageSize={5}
/>
</div>
</div>
);
}
}
代码中需要注意一下几点:
1、ListView组件里的dataSource是指长列表需要渲染的数据,代码中的this.state.list不是数组格式,而是databolb格式。只有而是databolb格式,listview组件才能正常渲染。代码中new ListView.DataSource()生成的即是一个空的databolb数据格式(图3中有databolb的格式)。
2、renderRow是从数据源(dataSource)中接受一条数据,以及它和它所在section的ID(图3中有rowData, sectionID, rowID)。返回一个可渲染的组件来为这行数据进行渲染。意思就是renderRow的作用是对一行行的数据进行渲染,它把dataSource的数据一条条的渲染并展示出来(本例中this.state.list中的每条数据都会经过ROW函数渲染,最终得到完整的渲染列表)。
3、数据源(dataSource)必须通过.cloneWithRows()进行赋值或者更新,该方法是databolb数据格式所拥有的方法,该方法的作用就是把数据变成databolb格式,并且把数据复制进来。
三、ListView如何更新渲染数据
本栗子中,如果点击'饮料'按钮,this.state.list通过 list:this.state.list.cloneWithRows({...this.state.secondArr})被更新。listview通过rowHasChanged函数控制列表的刷新,该函数会把原来的每一条数据row1与后面更新后的每条数据row2对比,当该函数返回true时列表刷新,当为false时列表不刷新。并且对比是对相应的位置上的数据对比,比如原来的第一条数据只和更新后的第一条数据相比。 对本栗子中,当我们点击'饮料'按钮,浏览器控制台输出如下:图4
列表效果:
图5
修改代码如下,使得rowHasChanged返回false,那么listview组件就不会更新<br>
export default class Test extends Component{
constructor(props:any){
super(props);
this.state={
list: new ListView.DataSource({
rowHasChanged :(row1: any, row2: any)=>{
console.log('row1', row1);
console.log('row2', row2);
return false;
}
}),
firstArr:['苹果','栗子','橘子','桃子','葡萄','葡萄'],
secondArr:['娃哈哈','健力宝','栗子','青岛','二锅头'],
}
}
控制台输出信息:
控制台输出如下:
图6
可以看到,由于rowHasChanged始终返回false导致listview没有更新,ROW函数就没有调用,因此列表里展示的依然是水果列表:
图7
总结了这么多,主要就是讲listview如何渲染数据,又是如何控制组建刷新的,希望可以帮到大家。小鹿加油!