import React from 'react' import axios from 'axios' //导入axios //导入navBar组件 import { NavBar, Icon, Toast } from 'antd-mobile' import './index.scss' import { getCurrentCity } from '../../utils' //导入react-virtualized组件 import { List, AutoSizer } from 'react-virtualized' import NavHeader from '../../components/NavHeader' // 数据格式化的方法 // list: [{}, {}] const formatCityData = (list) => { const cityList = {} // const cityIndex = [] // 1 遍历list数组 list.forEach((item) => { // 2 获取每一个城市的首字母 const first = item.short.substr(0, 1) // 3 判断 cityList 中是否有该分类 if (cityList[first]) { // 4 如果有,直接往该分类中push数据 // cityList[first] => [{}, {}] cityList[first].push(item) } else { // 5 如果没有,就先创建一个数组,然后,把当前城市信息添加到数组中 cityList[first] = [item] } }) // 获取索引数据 const cityIndex = Object.keys(cityList).sort() return { cityList, cityIndex, } } // 列表数据的数据源 const list = Array(100).fill('react-virtualized') const TITLE_HEIGHT = 36 const NAME_HEIGHT = 50 // 有房源的城市 const HOUSE_CITY = ['北京', '上海', '广州', '深圳'] class cityList extends React.Component { constructor(props) { super(props) this.state = { cityList: [], cityIndex: [], activeIndex: 0, } //创建ref对象 this.cityListComponent = React.createRef() } changeCity(curcity) { console.log(curcity) } //处理封装字母索引的方法 formDataCityIndex = (letter) => { switch (letter) { case '#': return '当前定位' case 'hot': return '热门城市' default: return letter.toUpperCase() } } async componentDidMount() { await this.getCityList() //提前计算每一行的高度 //注意这个方法的时候 保证list组件有数据了 // 调用 measureAllRows,提前计算 List 中每一行的高度,实现 scrollToRow 的精确跳转 // 注意:调用这个方法的时候,需要保证 List 组件中已经有数据了!如果 List 组件中的数据为空,就会导致调用方法报错! // 解决:只要保证这个方法是在 获取到数据之后 调用的即可。 this.cityListComponent.current.measureAllRows() } changeCity({ label, value }) { if (HOUSE_CITY.indexOf(label) > -1) { // 有 localStorage.setItem('hkzf_city', JSON.stringify({ label, value })) this.props.history.go(-1) } else { Toast.info('该城市暂无房源数据', 1, null, false) } } // 渲染每一行数据的渲染函数 // 函数的返回值就表示最终渲染在页面中的内容 rowRenderer({ key, // Unique key within array of rows index, // 索引号 isScrolling, // 当前项是否正在滚动中 isVisible, // 当前项在 List 中是可见的 style, // 注意:重点属性,一定要给每一个行数据添加该样式!作用:指定每一行的位置 }) { //获取每一行的索引号 const { cityIndex, cityList } = this.state const letter = cityIndex[index] //指定城市列表数据 return ( <div key={key} style={style} className="city"> <div className="title">{this.formDataCityIndex(letter)}</div> {/* <div className="name">上海</div> */} {cityList[letter].map((item) => ( <div className="name" onClick={() => this.changeCity(item)} key={item.value} > {item.label} </div> ))} </div> ) } async getCityList() { const res = await axios.get('http://localhost:8080/area/city?level=1') console.log(res, 'resss') const { cityList, cityIndex } = formatCityData(res.data.body) console.log(cityList, cityIndex) const hotRes = await axios.get('http://localhost:8080/area/hot') console.log(hotRes, 'hotRes') cityList['hot'] = hotRes.data.body cityIndex.unshift('hot') console.log(cityList, cityIndex, 'hotList') //获取当前定位城市 const curcity = await getCurrentCity() cityList['#'] = [curcity] cityIndex.unshift('#') this.setState({ cityList, cityIndex, }) } // 封装渲染右侧索引列表的方法 renderCityIndex() { // 获取到 cityIndex,并遍历其,实现渲染 const { cityIndex, activeIndex } = this.state return cityIndex.map((item, index) => ( <li className="city-index-item" key={item} onClick={() => { this.cityListComponent.current.scrollToRow(index) }} > <span className={activeIndex === index ? 'index-active' : ''}> {item === 'hot' ? '热' : item.toUpperCase()} </span> </li> )) } // 用于获取List组件中渲染行的信息 onRowsRendered = ({ startIndex }) => { // console.log('startIndex:', startIndex) if (this.state.activeIndex !== startIndex) { this.setState({ activeIndex: startIndex, }) } } getRowHeight({ index }) { // 索引标题高度 + 城市数量 * 城市名称的高度 // TITLE_HEIGHT + cityList[cityIndex[index]].length * NAME_HEIGHT const { cityList, cityIndex } = this.state return TITLE_HEIGHT + cityList[cityIndex[index]].length * NAME_HEIGHT } render() { return ( <div className="citylist"> <NavHeader>城市选择</NavHeader> {/* 城市列表 */} <AutoSizer> {({ width, height }) => ( <List ref={this.cityListComponent} width={width} height={height} rowCount={this.state.cityIndex.length} rowHeight={this.getRowHeight.bind(this)} rowRenderer={this.rowRenderer.bind(this)} onRowsRendered={this.onRowsRendered} /> )} </AutoSizer> {/* 右侧索引列表 */} {/* 1 封装 renderCityIndex 方法,用来渲染城市索引列表。 2 在方法中,获取到索引数组 cityIndex ,遍历 cityIndex ,渲染索引列表。 3 将索引 hot 替换为 热。 4 在 state 中添加状态 activeIndex ,指定当前高亮的索引。 5 在遍历 cityIndex 时,添加当前字母索引是否高亮的判断条件。 */} <ul className="city-index">{this.renderCityIndex()}</ul> </div> ) } } export default cityList
运行结果