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

news2024/11/16 7:22:45

文章目录

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


前言

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

一、 效果展示

在这里插入图片描述

二、相关模块

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 (
    <HomeChartBlock to="/block-list">
      {/* 使用ReactChartBlock组件展示Echarts图表 */}
      <ReactChartBlock
        option={parseOption(echartData, true)}
        notMerge
        lazyUpdate
        style={{
          height: "180px",
        }}
      ></ReactChartBlock>
    </HomeChartBlock>
  );
});
--------------------------------------------------------------------------------------------------------------
// @/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 }) => (
    <HomeStatisticItem>
      <div className={classNames("statistic-item-left-title")}>{data.name}</div>
      <div className={classNames("statistic-item-left-value")}>{data.value}</div>
    </HomeStatisticItem>
  );
  return (
    <>
      <HomeStatisticBlock>
        <div className={classNames("statistic-item")}>
          <div className={classNames("statistic-item-left")}>
            <StatisticItem data={echartsAndDataList[0]}></StatisticItem>
            <StatisticItem data={echartsAndDataList[1]}></StatisticItem>
          </div>
          <div className={classNames("statistic-item-right")}>
            {/* hash图表模拟 */}
            <HashRateEchart />
          </div>
        </div>
        <div className={classNames("statistic-item")}>
          <div className={classNames("statistic-item-left")}>
            <StatisticItem data={echartsAndDataList[2]}></StatisticItem>
            <StatisticItem data={echartsAndDataList[3]}></StatisticItem>
          </div>
          <div className={classNames("statistic-item-right")}>
            {/* hash图表模拟 */}
            <HashRateEchart />
          </div>
        </div>
      </HomeStatisticBlock>
    </>
  );
};
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";
// 使用
<StatisticBlock />

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 (
    <div className={classNames(styles.searchBlock)}>
      {/* 标题 */}
      <span className={classNames(styles.title)}>{t("common.Explorer")}</span>
      {/* 内容 */}
      <div className={classNames(styles.content)}>
        {/* 搜索组件 */}
        <Search hasButton />
      </div>
    </div>
  );
});
// 导出 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";
// 使用
<SearchBlock />

3. banner模块

功能分析

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

代码+详细注释

// @/pages/Home/Banner/index.tsx
import classNames from "classnames";
import styles from "./index.module.scss";
export default () => <div className={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";
// 使用
<Banner />

总结

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1909529.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【国产开源可视化引擎Meta2d.js】图元

图元 又称画笔Pen。图形表达的基本元素&#xff0c;组成图像的基本单元。 构成 每一个图元由ID、名字、类型、属性&#xff08;数据&#xff09;组成。 ID 名为“id”的特殊属性&#xff0c;图元实例&#xff08;画布上的图元对象&#xff09;的唯一标识。拖拽到画布或创建…

【最新鸿蒙应用开发】——Router页面路由

Router路由 页面路由指的是在应用程序中实现不同页面之间的跳转&#xff0c;以及数据传递。通过 Router 模块就可以实现这个功能. 1. 创建页面 之前是创建的文件&#xff0c;使用路由的时候需要创建页面&#xff0c;步骤略有不同 方法 1&#xff1a;直接右键新建Page&#xf…

Java项目:基于SSM框架实现的健康综合咨询问诊平台【ssm+B/S架构+源码+数据库+毕业论文】

一、项目简介 本项目是一套基于SSM框架实现的健康综合咨询问诊平台 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;eclipse或者idea 确保可以运行&#xff01; 该系统功能完善、界面美观、操作简单、…

js使用proxy代理监听控制事件

本文为proxy代理的实例应用&#xff0c;有关代理的内容可以参考&#xff1a; js语法---理解反射Reflect对象和代理Proxy对象 监听事件 要监听dom元素的事件&#xff0c;我们会采用回调触发的方式来执行操作&#xff0c; 而触发事件的过程很明显是一个异步操作&#xff0c;异…

activemq-CVE-2022-41678

Apache ActiveMQ Jolokia 后台远程代码执行漏洞 Apache ActiveMQ在5.16.5&#xff0c;5.17.3版本及以前&#xff0c;后台Jolokia存在一处任意文件写入导致的远程代码执行漏洞。 启动环境 admin/admin 方法一&#xff1a;利用poc 这个方法受到ActiveMQ版本的限制&#xff0c;因…

矢量数据库:LLMs外挂知识库

矢量数据库为管理高维数据提供了专门的解决方案&#xff0c;这对人工智能的上下文决策至关重要。但它们究竟是如何做到的呢&#xff1f; 介绍 信息有多种形式。有些信息是非结构化的&#xff0c;例如文本文档、图片和音频。有些则是结构化的&#xff0c;例如应用程序日志、表格…

【可视化大屏系列】Echarts之柱图绘制

本文为个人近期学习总结&#xff0c;若有错误之处&#xff0c;欢迎指出&#xff01; Echarts之柱图绘制 前言需求实现效果大概思路具体实现实现思路具体代码1.父组件写法2.子组件写法 附加1.同坐标系下&#xff0c;并排柱图绘制2.柱图下钻功能实现 前言 在前文页面布局、DataV…

HW期间——应急响应

01HW中应急响应的流程 001应急响应所处位置&#xff08;应急处置组&#xff09; 监控研判组发现的一些安全时间提供给应急处置组&#xff0c;应急处置组通过上机取证把线索给到溯源反制组。但是溯源反制组可能已经没有了&#xff0c;有些单位有&#xff0c;有些单位取消了。有…

标准扩散模型(standard diffusion)和潜在(latent diffusion)扩散模型的关键区别、对潜在扩散模型的认识

标准扩散模型(standard diffusion)和潜在(latent diffusion)扩散模型的关键区别、对潜在扩散模型的认识 1.两者的关键区别 潜在扩散模型通过在低维潜在空间的扩散过程&#xff0c;可以减少内存和计算的复杂性。而standard diffusion是在像素级别的空间(actual pixel space)进…

CSS上下悬浮特效

要实现一个上下悬浮的特效&#xff0c;可以使用CSS的keyframes规则和动画属性。以下是一个简单的示例&#xff1a; 代码示例 /* 定义一个名为floating的动画 */ keyframes floating {0% {transform: translateY(0); /* 初始位置 */}50% {transform: translateY(-4px); /* 向上…

吴恩达机器学习笔记2.1 - 什么是机器学习

吴恩达机器学习笔记2.1 - 什么是机器学习 最早的机器学习 1959年&#xff0c;亚瑟塞缪尔(Arthur Samuel)将机器学习定义为“Field of study that gives computers the ability to learn without being explicitly programmed”&#xff08;无需编程即可学习的研究领域&#xf…

ABAP BAPI_INCOMINGINVOICE_CREATE dump

在执行BAPI_INCOMINGINVOICE_CREATE 之后&#xff0c;正常生成了发票号&#xff0c;但是系统会dump 数据会回滚 dump如下 查阅后得知相关note:1894901 原因是在填写税行的时候&#xff0c;输入了多行&#xff0c;将数据合并为一行后即可 代码如下&#xff1a; ls_headerdat…

openlayers更改点坐标

我现在的需求是无人机点位根据ws传输的经纬度改变位置&#xff0c;在网上查了很多资料&#xff0c;终于是做出来了&#xff0c;如果有问题请指出。 效果图&#xff0c;无人机可以来回移动 这里是核心代码 // 添加飞机点位图层let vectorLayerpointfunction DronepointLayer()…

vscode设置左侧窗口字体大小

vscode设置左侧窗口字体大小 打开设置 在搜索框输入Zoom 修改这个值即可放大相关字体

从数字化营销与运营视角:看流量效果的数据分析

基于数据打通的“全链路”营销是当下的“时髦”&#xff0c;应用它的前提是什么&#xff1f;深度营销和运营的关键数据如何获得&#xff1f;如何利用数据进行更精准的营销投放&#xff1f;如何利用数据优化投放的效果&#xff1f;如何促进消费者的转化&#xff0c;以及激活留存…

【js面试题】深入理解尾递归及其在JavaScript中的应用

面试题&#xff1a;举例说明尾递归的理解&#xff0c;以及应用场景 引言&#xff1a; 在编程中&#xff0c;递归是一种常见的解决问题的方法&#xff0c;它允许函数调用自身来解决问题。然而&#xff0c;递归如果不当使用&#xff0c;可能会导致栈溢出错误&#xff0c;特别是在…

无损音频格式 FLAC 转 MP3 音频图文教程

音频文件的格式多样&#xff0c;每种格式都有其独特的特点与适用场景。FLAC&#xff08;Free Lossless Audio Codec&#xff09;&#xff0c;作为一种无损音频压缩格式&#xff0c;因其能够完美保留原始音频数据的每一个细节而备受音频发烧友和专业人士的青睐。 然而&#xff0…

代码随想录打卡第十八天

代码随想录–二叉树部分 day 17 休息日 day 18 二叉树第五天 文章目录 代码随想录--二叉树部分一、力扣654--最大二叉树二、力扣617--合并二叉树三、力扣700--二乘树中的搜素四、力扣98--验证二叉搜索树 一、力扣654–最大二叉树 代码随想录题目链接&#xff1a;代码随想录 给…

双系统ubuntu20.04扩容

windows端 打开磁盘管理器&#xff0c;选择需要的盘点击压缩卷 点击未分配的盘&#xff0c;新建简单卷&#xff0c;一致点击下一步即可&#xff0c;记住分配的大小容量 ubuntu端 lsblk 查看所有的磁盘&#xff0c;可以看到新增为nvme0n1p4、nvme1n1p2 win分配的格式为NTFS&a…

Idea-单个窗口导入并开启多个module项目

前言 大家是否有过这样的困扰&#xff0c;我们每次打开一个项目就需要单开一个idea窗口&#xff0c;项目少时了还好&#xff0c;一旦涉及多个项目间服务调用&#xff0c;特别是再包括网关、注册中心、前端web服务&#xff0c;需要开启的窗口就会是一大批&#xff0c;每次切换的…