04-HK 自定义城市选择列表

简介: 本文是 [hkzf](https://github.com/thomaslwq/hkzf.git) 移动端 的系列教程,旨在通过一系列的文章来帮助初学者快速掌握基于React技术栈的项目开发。

04-HK 自定义城市选择列表

本文是 hkzf 移动端 的系列教程,旨在通过一系列的文章来帮助初学者快速掌握基于React技术栈的项目开发。

需求分析

自定义城市列表分成了左右两部分。左边分成三个部分,分别是当前定位,热门城市,以及按照A,B,C,D....字母顺序排列的的城市列表。左边列表滚动,右边字母索引跟着滚动;右边字母索引被点击,左边城市列表滚动到对应的字母索引处。点击列表,选中城市。

实现

构造需要的城市数据结构列表

[{"当前定位":""},{"热门城市":["广州","北京"..]},{A:[....]}]

    getAllCities = async (params) => {

        //当前定位城市
        const { mapReducer } = store.getState();
        const cityName = mapReducer.cityName;

        // 获取所有城市
        let allCities = (await axios.get("/area/city?level=1")).body;
        //获取热门城市
        const hotCities = (await axios.get("/area/hot")).body;

        let totalCity = [
            { "当前定位": [cityName] },
            { "热门城市": hotCities.map(v => v.label) }
        ];
        // 思考一下,还差那些内容 allCities A:[....]
        //[{"当前定位":""},{"热门城市":["广州","北京"..]},{A:[....]}]
        //先做一个排序 ab ac ad ba bb ...
        allCities = allCities.sort(function (a, b) {
            return a.short.localeCompare(b.short);
        })
        //{A:[....],B:[....],C:[...]}
        allCities.forEach(v => {
            //取到简称里面首字母的大写
            let firstLetter = v.short[0].toUpperCase();
            //判断首字母是否在totalCity里面已经出现
            let index = totalCity.findIndex(item => {
                if (item[firstLetter]) {
                    return true;
                } else {
                    return false;
                }
            })
            if (index === -1) {
                //例如没有找到A [{},{"A":[v.label]}]
                totalCity.push(
                    { [firstLetter]: [v.label] }
                );
            } else {
                totalCity[index][firstLetter].push(v.label)
            }
        });
        let keyArr = totalCity.map(v => Object.keys(v)[0]);
        keyArr[0] = "#";
        keyArr[1] = "热";
        this.setState({
            totalCity, keyArr
        })
    }

使用 react-virtualized 进行长列表的渲染

安装 react-virtualized

npm install react-virtualized

城市列表

 <div className="list_content" >
                    <AutoSizer>
                        {({ height, width }) => (
                            <List
                                ref={this.MainList} //非受控表单
                                height={height}
                                rowCount={this.state.totalCity.length}
                                rowHeight={this.rowHeight}
                                rowRenderer={this.rowRenderer}
                                onRowsRendered={this.onRowsRendered}
                                width={width}
                                scrollToAlignment="start" // 对齐方式, 不加的话 点击右侧的字母,左侧 列表 滚动的位置不对
                            />
                        )}
                    </AutoSizer>

                </div>

渲染右侧字母列表

                {/* 首字母缩写开始 */}
                <div className="key_list">
                    {
                        this.state.keyArr.map( (v,i) => {
                        return <div 
                        onClick={this.onKeyLetterClick.bind(this,i)}
                        className={"key_item " + ( i===this.state.selectIndex ? "active":"")} key={v}>
                        {v}</div>
                        })
                    }
                </div>

                {/* 首字母缩写结束 */}

每一行的渲染和点击事件

    rowRenderer = ({ key, index, style }) => {
        //{"热门城市":["广州","上海"]}

        let item = this.state.totalCity[index];
        let item_name = Object.keys(item)[0];
        return (
            <div key={key} style={style}>
                <div className="city_list_name">
                    {item_name}
                </div>
                <div className="city_list_content" >
                    {
                        item[item_name].map((v, i) => {
                            return <div key={i} onClick={this.itemOnClick.bind(this, v)} className="list_item">{v}</div>
                        })
                    }
                </div>
            </div>
        );
    }
    itemOnClick = (v) => {
        store.dispatch(getCityNameAction(v));
        window.history.go(-1);
    }

    rowHeight = ({ index }) => {
        let item = this.state.totalCity[index];
        return (Object.values(item)[0].length + 1) * 40;
    }
    onKeyLetterClick = (index) => {
        this.MainList.current.scrollToRow(index);
        this.setState({
            selectIndex:index
        })
    }
    onRowsRendered = ({startIndex}) => {
        this.setState({
            selectIndex:startIndex
        })
    }
    
目录
相关文章
Java 通过IP获取对应的国家省份城市经纬度(离线文件方案)
一. 除了调用接口查询城市, 还可以通过离线文件查询城市, 使用GeoLite2 City库 二. 离线库下载地址: https://dev.maxmind.com/geoip/geoip2/geolite2/ 点击如下位置下载压缩文件 文件解压后有一个文件名为GeoLite2-City.
|
4月前
Map——全国省市区EXCEL表格(包含code)
Map——全国省市区EXCEL表格(包含code)
77 0
|
7月前
|
定位技术 API
通过经纬度获得地址与城市名称(原创)
通过经纬度获得地址与城市名称(原创)
243 3
|
前端开发 JavaScript
Select2(4.0.6)城市搜索
实现了城市列表的前端搜索,输入汉字、拼音首字母均可搜索,前端搜索。
913 0
Select2(4.0.6)城市搜索
|
数据安全/隐私保护
使用易路代理yiluproxy时,出现不是自己选定的城市该怎么办?
使用易路代理yiluproxy时,出现不是自己选定的城市该怎么办?
|
JSON 定位技术 数据格式
根据现有IP地址获取其地理位置(省份,城市等)的方法
根据现有IP地址获取其地理位置(省份,城市等)的方法
1216 0
DLA新增函数发布:手机号查询所属省、城市、运营商
概述 本月,Data Lake Analytics(https://www.aliyun.com/product/datalakeanalytics,https://et.aliyun.com/bdad/datalake)发布了手机号查询所属省、城市、运营商的内置函数。