React实现长列表
最近学习React,做的小练习
功能:
1,城市列表展示
2,使用索引快速定位相应的城市列表部分,滚动城市列表,索引跟随定位
3,点击城市名称切换城市
代码如下:
import React from "react";
import "./index.scss";
import { useNavigate } from "react-router-dom";
import { Toast } from "antd-mobile";
import request from "../../request";
import { getCurrenCity } from "../../utils/index";
import { List, AutoSizer } from "react-virtualized";
import NavHeader from "../../components/NavHeader/index";
export default function Citylist() {
// 索引(A,B……)的高度
const TITLE_HEIGHT = 36;
// 每个城市名称的高度
const NAME_HEIGHT = 50;
// 有房源的城市
const HOUSE_CITY = ["北京", "上海", "广州", "深圳"];
const navigate = useNavigate();
let hotCity = [];
const cityListComponent = React.useRef();
const [currentIndex, setCurrentIndex] = React.useState(0);
const [cityList, setCityList] = React.useState({});
const [cityIndex, setCityIndex] = React.useState([]);
// 初始化
React.useEffect(() => {
getCityList();
getHotCityList();
setTimeout(() => {
cityListComponent.current.measureAllRows();
}, 1000);
}, []);
// 获取城市列表数据
const getCityList = () => {
const params = { params: { level: 1 } };
request.get("/area/city", params).then((res) => {
if (res.body.length > 0) {
// console.log("城市列表数据",res.body)
const { cityList, cityIndex } = formatData(res.body);
// console.log("数据格式化=》", cityList, cityIndex);
setCityIndex(cityIndex);
setCityList(cityList);
}
});
};
// 获取热门城市数据
const getHotCityList = () => {
request.get("/area/hot").then((res) => {
if (res.body.length > 0) {
// console.log("热门城市=》", res.body);
hotCity = res.body;
}
});
};
// 格式化城市列表数据
const formatData = (list) => {
let cityList = {};
let cityIndex = [];
// 渲染城市列表的数据格式为:
// {a:[{},{}],b:[],……}
list.forEach((item) => {
const key = item.short.substr(0, 1);
if (cityList[key]) {
cityList[key].push(item);
} else {
cityList[key] = [item];
}
});
// 渲染右侧索引的数据格式
// ['a','b',……]
cityIndex = Object.keys(cityList).sort();
// 添加热门城市
cityList["hot"] = hotCity;
cityIndex.unshift("hot");
// 添加当前定位城市
getCurrenCity().then((data) => {
cityList["#"] = [data];
cityIndex.unshift("#");
});
return { cityList, cityIndex };
};
// 格式化城市索引
const formatCityIndex = (letter) => {
switch (letter) {
case "#":
return "当前定位";
case "hot":
return "热门城市";
default:
return letter.toUpperCase(); // A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
}
};
// 计算每行的高度
const getRowHeight = ({ index }) => {
const list = cityList[cityIndex[index]];
return list.length * NAME_HEIGHT + TITLE_HEIGHT;
};
// 渲染索引
const renderIndex = () => {
return cityIndex.map((item, index) => (
<li
key={item}
className="city-index-item"
onClick={() => {
setCurrentIndex(index);
return cityListComponent.current.scrollToRow(index);
}}
>
<span className={currentIndex === index ? "index-acitve" : ""}>
{item === "hot" ? "热" : item.toUpperCase()}
</span>
</li>
));
};
const rowRenderer = ({ key, index, style }) => {
const letter = cityIndex[index];
return (
<div key={key} style={style} className="city">
<div className="title">{formatCityIndex(letter)}</div>
{cityList[letter].map((item) => {
return (
<div
key={item.value}
className="name"
onClick={() => changeItem(item)}
>
{item.label}
</div>
);
})}
</div>
);
};
const changeItem = ({ label, value }) => {
if (HOUSE_CITY.includes(label)) {
localStorage.setItem("hkzf_city", JSON.stringify({ label, value }));
navigate("/home");
} else {
Toast.show({
content: "暂无房源信息",
});
}
};
const onRowsRendered = ({ startIndex }) => {
if (startIndex !== currentIndex) {
setCurrentIndex(startIndex);
}
};
return (
<div className="cityList_main">
<NavHeader title="城市选择" />
<AutoSizer>
{({ height, width }) => (
<List
ref={cityListComponent}
width={width}
height={height}
rowCount={cityIndex.length}
rowHeight={getRowHeight}
rowRenderer={rowRenderer}
onRowsRendered={onRowsRendered}
scrollToAlignment="start"
/>
)}
</AutoSizer>
<ul className="city-index">{renderIndex()}</ul>
</div>
);
}
相关视频:https://www.bilibili.com/video/BV1gh411U7JD?spm_id_from=333.788.videopod.episodes&vd_source=2f48f471bbeafdcd207f29dadcc97a5d&p=131
gitee地址:https://gitee.com/abcdfdewrw/react_hkzf
第三方组件:react-virtualized长列表
难点:数据格式处理,react-virtualized组件在项目中的使用