React+TS前台项目实战(二十七)-- 首页响应式构建之banner、搜索、统计模块布局

2024-07-12 1250阅读

文章目录

  • 前言
  • 一、 效果展示
  • 二、相关模块
    • 1. Statistic统计模块
      • 功能分析
      • 代码+详细注释
      • 使用方式
      • 2. Search搜索模块
        • 功能分析
        • 代码+详细注释
        • 使用方式
        • 3. banner模块
          • 功能分析
          • 代码+详细注释
          • 使用方式
          • 总结

            前言

            前面我们已经封装了这个项目基本要用到的全局组件了,现在就开始进入页面构建以及接口对接阶段了。首先,我们先来构建首页响应式布局,接下来会讲到真实接口对接,搭配react-query实现轮询,并使用memo,useMemo,usePrevious等钩子来优化页面,避免不必要的重新渲染。

            一、 效果展示

            React+TS前台项目实战(二十七)-- 首页响应式构建之banner、搜索、统计模块布局

            二、相关模块

            1. Statistic统计模块

            功能分析

            该模块主要为了展示基本数据统计,以及Echart图表统计

            代码+详细注释

            (1) 图表统计模块抽离

            // @/pages/Home/StaticBlock/HashRateEchart/index.tsx
            import { memo } from "react";
            import BigNumber from "bignumber.js";
            import "echarts/lib/chart/line";
            import "echarts/lib/component/title";
            import echarts from "echarts/lib/echarts";
            import { useTranslation } from "react-i18next";
            import { HomeChartBlock } from "./styled";
            import { ReactChartBlock } from "@/components/Echarts/common";
            // 使用useOption函数生成Echarts配置对象
            const useOption = () => {
              const { t } = useTranslation();
              return (data: any, useMiniStyle: boolean): echarts.EChartOption => {
                return {
                  color: ["#ffffff"], // 颜色设置
                  title: {
                    text: "图表y轴时间", // 标题
                    textAlign: "left", // 标题对齐方式
                    textStyle: {
                      color: "#ffffff", // 字体颜色
                      fontSize: 14, // 字体大小
                      fontWeight: "lighter", // 字体粗细
                      fontFamily: "Lato", // 字体类型
                    },
                  },
                  grid: {
                    left: useMiniStyle ? "1%" : "2%", // 图表距离容器左边的距离
                    right: "3%", // 图表距离容器右边的距离
                    top: useMiniStyle ? "20%" : "15%", // 图表距离容器顶部的距离
                    bottom: "2%", // 图表距离容器底部的距离
                    containLabel: true, // 是否包含坐标轴的刻度标签
                  },
                  xAxis: [
                    {
                      axisLine: {
                        lineStyle: {
                          color: "#ffffff", // x轴颜色
                          width: 1, // x轴宽度
                        },
                      },
                      data: data.map((item: any) => item.xTime), // x轴数据
                      axisLabel: {
                        formatter: (value: string) => value, // x轴坐标标签格式化
                      },
                      boundaryGap: false, // 是否留空
                    },
                  ],
                  yAxis: [
                    {
                      position: "left",
                      type: "value",
                      scale: true,
                      axisLine: {
                        lineStyle: {
                          color: "#ffffff", // y轴颜色
                          width: 1, // y轴宽度
                        },
                      },
                      splitLine: {
                        lineStyle: {
                          color: "#ffffff", // y轴分割线颜色
                          width: 0.5, // y轴分割线宽度
                          opacity: 0.2, // y轴分割线透明度
                        },
                      },
                      axisLabel: {
                        formatter: (value: string) => new BigNumber(value), // y轴坐标标签格式化
                      },
                      boundaryGap: ["5%", "2%"], // y轴两侧留空
                    },
                    {
                      position: "right",
                      type: "value",
                      axisLine: {
                        lineStyle: {
                          color: "#ffffff", // y轴颜色
                          width: 1, // y轴宽度
                        },
                      },
                    },
                  ],
                  series: [
                    {
                      name: t("block.hash_rate"), // 系列名称
                      type: "line", // 系列类型
                      yAxisIndex: 0, // y轴索引
                      lineStyle: {
                        color: "#ffffff", // 系列颜色
                        width: 1, // 系列线条宽度
                      },
                      symbol: "none", // 系列标记的图形类型
                      data: data.map((item: any) =>
                        new BigNumber(item.yValue).toNumber()
                      ), // 系列数据
                    },
                  ],
                };
              };
            };
            // HomeChartBlock组件
            export default memo(() => {
              // 后期改为真实接口请求
              const echartData = [
                { xTime: "2020-01-01", yValue: "1500" },
                { xTime: "2020-01-02", yValue: "5220" },
                { xTime: "2020-01-03", yValue: "4000" },
                { xTime: "2020-01-04", yValue: "3500" },
                { xTime: "2020-01-05", yValue: "7800" },
              ];
              // 解析配置对象
              const parseOption = useOption();
              return (
                
                  {/* 使用ReactChartBlock组件展示Echarts图表 */}
                  parseOption(echartData, true)}
                    notMerge
                    lazyUpdate
                    style={{
                      height: "180px",
                    }}
                  
                
              );
            });
            --------------------------------------------------------------------------------------------------------------
            // @/pages/Home/StaticBlock/HashRateEchart/styled.tsx
            import styled from "styled-components";
            import Link from "@/components/Link";
            export const HomeChartBlock = styled(Link)`
              canvas {
                cursor: pointer;
              }
            `;
            export const ChartLoadingBlock = styled.div`
              height: 100%;
              display: flex;
              align-items: center;
              justify-content: center;
              .no-data {
                font-size: 18px;
              }
            `;
            

            (2)引入统计图表

            // @/pages/Home/StatisticBlock/index.tsx
            import { FC } from "react";
            import classNames from "classnames";
            import { useTranslation } from "react-i18next";
            import HashRateEchart from "./HashRateEchart/index";
            import { HomeStatisticBlock, HomeStatisticItem } from "./styled";
            import { useStatistics } from './hook'
            const StatisticBlock: FC = () => {
              // 区块链统计数据类型声明
              interface EchartsAndData {
                name: string;
                value: string;
              }
              // 使用区块链统计数据
              const useEchartsAndDataList = (): EchartsAndData[] => {
                const { t } = useTranslation();
                const statistics = useStatistics()
                return [
                  {
                    name: t("home.echartsAndData.name1"),
                    value: t(statistics.value1),
                  },
                  {
                    name: t("home.echartsAndData.name2"),
                    value: t(statistics.value2),
                  },
                  {
                    name: t("home.echartsAndData.name3"),
                    value: t(statistics.value3),
                  },
                  {
                    name: t("home.echartsAndData.name4"),
                    value: t(statistics.value4),
                  },
                ];
              };
              // 使用区块链统计数据
              const echartsAndDataList = useEchartsAndDataList();
              // 单个统计渲染组件
              const StatisticItem = ({ data }: { data: EchartsAndData }) => (
                
                  classNames("statistic-item-left-title")}{data.name}
                  classNames("statistic-item-left-value")}{data.value}
                
              );
              return (
                
                  
                    classNames("statistic-item")}
                      classNames("statistic-item-left")}
                        echartsAndDataList[0]}
                        echartsAndDataList[1]}
                      
                      classNames("statistic-item-right")}
                        {/* hash图表模拟 */}
                        
                      
                    
                    classNames("statistic-item")}
                      classNames("statistic-item-left")}
                        echartsAndDataList[2]}
                        echartsAndDataList[3]}
                      
                      classNames("statistic-item-right")}
                        {/* hash图表模拟 */}
                        
                      
                    
                  
                
              );
            };
            export default StatisticBlock;
            --------------------------------------------------------------------------------------------------------------
            // @/pages/Home/StatisticBlock/styled.tsx
            import styled from "styled-components";
            import variables from "@/styles/variables.module.scss";
            export const HomeStatisticBlock = styled.div`
              width: 100%;
              height: 207px;
              display: flex;
              margin-bottom: 20px;
              .statistic-item {
                display: flex;
                align-items: center;
                justify-content: space-between;
                flex: 1;
                background: #232323;
                @media (max-width: ${variables.extraLargeBreakPoint}) {
                  flex-direction: column;
                }
                @media (max-width: ${variables.mobileBreakPoint}) {
                }
                .statistic-item-left {
                  flex: 1;
                  width: 100%;
                  height: 100%;
                }
                .statistic-item-right {
                  flex: 2;
                  width: 100%;
                  height: 100%;
                  padding: 10px;
                  // background: linear-gradient(304deg, #6e85e0 2%, #577cdb 48%, #486ecc 99%);
                  @media (max-width: ${variables.extraLargeBreakPoint}) {
                  }
                  @media (max-width: ${variables.mobileBreakPoint}) {
                  }
                }
                &:last-child {
                  background: #484e4e;
                }
              }
              @media (max-width: ${variables.extraLargeBreakPoint}) {
                height: 310px;
              }
              @media (max-width: ${variables.mobileBreakPoint}) {
                flex-direction: column;
                height: auto;
              }
            `;
            export const HomeStatisticItem = styled.div`
              padding: 30px;
              display: flex;
              justify-content: space-between;
              flex-direction: column;
              color: #fff;
              .statistic-item-left-title {
                font-size: 14px;
                margin-bottom: 5px;
              }
              .statistic-item-left-value {
                font-size: 18px;
                font-weight: bold;
              }
              @media (max-width: ${variables.extraLargeBreakPoint}) {
                padding: 15px 30px;
                flex-direction: row;
                margin-bottom: 0;
                .statistic-item-left-value {
                  font-size: 16px;
                }
              }
              @media (max-width: ${variables.mobileBreakPoint}) {
                padding: 10px 20px;
              }
            `;
            

            使用方式

            // 引入
            import StatisticBlock from "./SearchBlock";
            // 使用
            
            

            2. Search搜索模块

            功能分析

            (1)引入全局封装的搜索组件,抽离成一个灵巧组件

            (2)使用国际化语言

            代码+详细注释

            // @/pages/Home/SearchBlock/index.tsx
            import { FC, memo } from "react";
            import { useTranslation } from "react-i18next";
            import classNames from "classnames";
            import styles from "./index.module.scss";
            import Search from "@/components/Search";
            // SearchBlock 组件
            const SearchBlock: FC = memo(() => {
              // 获取 i18n 的翻译函数
              const [t] = useTranslation();
              return (
                classNames(styles.searchBlock)}
                  {/* 标题 */}
                  classNames(styles.title)}{t("common.Explorer")}
                  {/* 内容 */}
                  classNames(styles.content)}
                    {/* 搜索组件 */}
                    
                  
                
              );
            });
            // 导出 SearchBlock 组件
            export default SearchBlock;
            --------------------------------------------------------------------------------------------------------------
            // @/pages/Home/SearchBlock/index.module.scss
            @import "@/styles/variables.module";
            .searchBlock {
              display: flex;
              align-items: center;
              margin: 20px 0;
              .title {
                display: flex;
                align-items: center;
                font-weight: 800;
                font-size: 20px;
                @media (max-width: $extraLargeBreakPoint) {
                  margin-bottom: 20px;
                }
                @media (max-width: $mobileBreakPoint) {
                  font-size: 16px;
                  margin-bottom: 14px;
                }
              }
              .content {
                flex: 1;
                margin-left: 16px;
                @media (max-width: $extraLargeBreakPoint) {
                  width: 100%;
                  margin-left: 0;
                }
              }
              @media (max-width: $extraLargeBreakPoint) {
                display: block;
              }
            }
            

            使用方式

            // 引入
            import SearchBlock from "./SearchBlock";
            // 使用
            
            

            3. banner模块

            功能分析

            banner展示图,此处PC端和移动端采用不同的图片

            代码+详细注释

            // @/pages/Home/Banner/index.tsx
            import classNames from "classnames";
            import styles from "./index.module.scss";
            export default () => classNames(styles.banner)} /;
            --------------------------------------------------------------------------------------------------------------
            // @/pages/Home/Banner/index.module.scss
            @import "@/styles/variables.module";
            $backgroundColor: #232323;
            .banner {
              width: 100%;
              height: 200px;
              background: url("./assets/banner.svg") no-repeat center center / auto 100%;
              background-color: $backgroundColor;
              position: relative;
              @media (max-width: $mobileBreakPoint) {
                background-image: url("./assets/banner_phone.svg");
              }
            }
            

            使用方式

            // 引入
            import Banner from "./Banner";
            // 使用
            
            

            总结

            下一篇讲【首页响应式构建之区块、交易列表布局】。关注本栏目,将实时更新。

VPS购买请点击我

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

目录[+]