当前位置: 首页 > article >正文

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组件在项目中的使用


http://www.kler.cn/a/466818.html

相关文章:

  • 华为数通考试模拟真题(附带答案解析)题库领取
  • http性能测试命令ab
  • vue3+Echarts+ts实现甘特图
  • 系统架构师考试-ABSD基于架构的设计方法
  • 下载b站高清视频
  • 『SQLite』创建、附加、分离、备份及恢复数据库
  • python的reload
  • Java重要面试名词整理(十四):elasticsearch
  • halcon中的阈值分割
  • 计算机视觉之三维重建-摄像机标定
  • vue中使用exceljs组件库导入导出json到excel
  • Vue3苦逼的学习之路
  • 【U8+】用友U8软件中,出入库流水输出excel的时候提示报表输出引擎错误。
  • 探索AI在地质科研绘图中的应用:ChatGPT与Midjourney绘图流程与效果对比
  • Postman[1] 入门——安装及启动
  • elementui table 表格 分页多选,保持选中状态
  • AEM电解水制氢技术在综合能源站的场景适应性
  • HTML——70. 多行文本输入框
  • 探索Flutter 3.0:跨平台开发的未来
  • JVM实战—9.线上FGC的几种案例
  • 深入Android架构(从线程到AIDL)_08 认识Android的主线程
  • windows安装rsync Shell语句使用rsync
  • hot100_189. 轮转数组
  • 25.1.3
  • GoFullPage插件:让网页截图变得简单又高效
  • el-form+el-date-picker组合使用时候的回显问题