文章目录
- 前言
- 一、 效果展示
- 二、相关模块
- 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图表 */}<ReactChartBlockoption={parseOption(echartData, true)}notMergelazyUpdatestyle={{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 />
总结
下一篇讲【首页响应式构建之区块、交易列表布局】。关注本栏目,将实时更新。