react 列表懒渲染
使用 react-virtualized 实现
使用步骤:
-
使用npm进行安装
npm install react-virtualized
-
引入它的 css 样式文件
import '../node_modules/react-virtualized/styles.css'
-
使用Link和AutoSizer 组件实现,懒渲染
import { List, AutoSizer } from 'react-virtualized'
-
List 组件的使用
内置方法:- scrollToRow(方法)
这个方法传入索引值,他会查找传入索引的行,显示到页面可视区域,结合页面索引点击快速导航使用 - scrollToAlignment(属性)
结合上个方法,当页面可视区更新时,显示到最顶部还是底部还是居中
他有四个值可选:start 最上面、center居中、end最底部、auto默认自适应
如果想要调用他的内置方法必须使用ref获取它(List组件)
import React from 'react' // 使用react创建一个ref this.ListRef = React.createRef()
// 因为当前height值和width值不确定,所以要使用AutoSizer组件来获取当前窗体的宽高。 <AutoSizer>{({width,height})=>{ // 将List组件放在这个组件里面 <List ref={ListRef} height={height} //设置整个列表的高度 width={width} // 设置整个列表的宽度 rowHight={100} //设置每行的宽度(每循环一个单位的高度),可以是一个变量,也可以是一个函数去计算每行的高度,一般使用函数计算好return 回来一个变量 rowCount={} // 设置循环生成次数(多少行) rowRenderer={} // 渲染每行的dom,值为函数,函数中有一个参数,是一个对象,对象中包含当前索引(index),随机生成的key值,和style样式,循环时必须要加入style样式,否则设置的样式属性不生效 onRowsRendered={} // 绑定一个函数,只要列表滚动就会触发这个函数,并且有一个参数,参数里面有当前最上面渲染的元素索引。 scrollToAlignment="start" /> }}</AutoSizer>
- scrollToRow(方法)
完整代码
import React, { PureComponent } from "react";
import { getCityHot, getCityList } from "../../api/home";
import getPosition from "../../utils/GetPosition";
// import { NavBar, Icon } from 'antd-mobile'
import { List, AutoSizer } from 'react-virtualized'
import NavBar from '../../components/Navbar'
import '../../components/TabBar/css/iconfont.css'
import './index.scss'
const TITLE_HEIGHT = 30
const CITY_ITEM_HEIGHT = 45
export default class CityList extends PureComponent {
constructor() {
super()
this.Refs = React.createRef()
}
state = {
CityGroupList: {},
CityGroupIndex: [],
currentCity: {},
CityIndexselect: 0
}
render () {
return (
<div className="CityList">
{/* 头部导航部分 */}
<div className='NavBar'>
<NavBar ReturnPage={() => { this.props.history.go(-1) }}>选择城市</NavBar>
</div>
<AutoSizer>
{({ width, height }) => {
return (
<List
ref={this.Refs}
height={height}
width={width}
rowHeight={this.getHight}
rowCount={this.state.CityGroupIndex.length}
rowRenderer={this.renderCityList}
onRowsRendered={this.rowsRundered.bind(this)}
scrollToAlignment="start"
/>
)
}}
</AutoSizer>
<div className="CityIndexNav">
<ul>
{
this.renderCityIndexNav()
}
</ul>
</div>
</div>
)
}
async componentDidMount () {
await this.setCityGroup()
this.Refs.current.measureAllRows()
}
rowsRundered ({ startIndex }) {
// console.log(startIndex)
this.setState({
CityIndexselect: startIndex
})
}
// 懒渲染所有城市
renderCityList = ({
key,
index,
style
}) => {
let cityIndex = this.state.CityGroupIndex[index]
let citys = this.state.CityGroupList[cityIndex]
return (
<div className='indexItem' key={key} style={style}>
<div className="title">
{this.renderCityIndex(cityIndex)}
</div>
<div className="content">
{this.renderCityItem(citys, cityIndex)}
</div>
</div>
)
}
// 城市索引点击设置选中状态
CityIndexActive (index) {
this.Refs.current.scrollToRow(index)
this.setState({
CityIndexselect: index
})
}
// 渲染城市索引导航列表
renderCityIndexNav () {
return this.state.CityGroupIndex.map((item, index) => {
return <li onClick={this.CityIndexActive.bind(this, index)} className={this.state.CityIndexselect === index ? 'CityActive' : ''} key={item}>{item === 'hot' ? '热' : item.toUpperCase()}</li>
})
}
// 渲染某个城市索引
renderCityIndex (cityIndex) {
if (cityIndex === "#") return <span className='special-title'>当前城市</span>
if (cityIndex === 'hot') return <span className='special-title'>热门城市</span>
return cityIndex.toUpperCase()
}
// 渲染每个索引下的所有城市
renderCityItem (citys, cityIndex) {
if (cityIndex === '#') {
return (<div className="current-city">
<div className="currentPositionIcon">
<span className="iconfont icon-location"></span>
<span>{citys[0].label}</span>
</div>
<div className="RefreshIcon">
<span className="iconfont icon-shuaxin"></span>
</div>
</div>)
}
return citys.map(item => {
return (
<div onClick={this.selectCity.bind(this, item)} key={item.value} className='city-item'>{item.label}</div>
)
})
}
// 选择城市
selectCity ({ label, value }) {
sessionStorage.setItem('51_home', JSON.stringify({ label, value }))
this.props.history.push('/')
}
// 获取每行的高度
getHight = ({ index }) => {
// console.log(this.state.CityGroupList[])
// return index
let cityIndex = this.state.CityGroupIndex[index]
return TITLE_HEIGHT + this.state.CityGroupList[cityIndex].length * CITY_ITEM_HEIGHT
}
// 格式化城市数据,城市列表和城市首字母索引,和热门城市,整合成一个对象
async setCityGroup () {
const currentCity = await getPosition()
const { data: { body: CityList } } = await getCityList()
const { data: { body: CityHot } } = await getCityHot()
let CityGroupList = {}
CityList.forEach(item => {
if (CityGroupList[item.short[0]]) {
CityGroupList[item.short[0]].push(item)
} else {
CityGroupList[item.short[0]] = [item]
}
});
const CityGroupIndex = Object.keys(CityGroupList).sort()
CityGroupIndex.unshift('hot')
CityGroupIndex.unshift('#')
CityGroupList['#'] = [currentCity]
CityGroupList['hot'] = CityHot
await this.setState({
CityGroupIndex,
CityGroupList,
currentCity,
})
}
}