React实例之完善布局菜单(三)

news2024/9/19 4:18:31

接着上篇的内容继续。规划界面布局。界面分为三个部分,左边为菜单部分,右边上部有个 80 px 高度左右的功能区,下面是主内容区。 依据这个设计,我们进行下面的步骤:

在 SMenu项目中创建一个目录: SLayout, 这个目录里我们存储各种布局,我们先来示例一种,其它的我们根据需要可以自行设计。在这个目录中创建FullPage.jsx 文件

// SLayout/FullPage.jsx

import Box from '@mui/material/Box';
import Paper from '@mui/material/Paper';

function FullPage({ sideMenu, pageHeader , children }) {
    return (
        <Paper className='d-flex overflow-hidden position-absolute w-100 h-100 p-0 m-0'>
            <Box className='h-100'>
                {
                    sideMenu
                }
            </Box>

            <Box className='d-flex overflow-hidden position-relative flex-grow-1'>
                <Box className="d-flex flex-column overflow-auto p-0 m-0 position-relative flex-grow-1 flex-nowrap">
                    <Box
                        className="w-100 p-3 border-bottom"
                        sx={{ height: 68 }}
                    >
                       { pageHeader }
                    </Box>
                    <Box className="p-0 w-100 h-100">
                        {children }
                    </Box>
                </Box>
            </Box>
        </Paper>
    )
}

export default FullPage;

这个没什么好说的,就是主要就是利用Flex的特殊用 Bootstrap 对界面进行布局,没什么难度。

现在我们利用这个布局把所用的元素添加进来。在SMenu项目目录下创建一个测试文件: SideMenuTest.jsx :

// SideMenuTest.jsx
import VerticalSplitIcon from '@mui/icons-material/VerticalSplit';
import Box from '@mui/material/Box';
import SideMenu from "./SMenu/SideMenu";
import SToggleButton from './SMenu/_SToggleButton';
import { useSideMenuBadgeUpdate } from './SMenu/_SMenuHooks';
import FullPage from './SLayout/FullPage';
import Typography from '@mui/material/Typography';
import Stack from '@mui/material/Stack';
import ToggleThemeButton from './STheme/TaggleThemeButton';

function SideMenuTest() {
    const updateBadge = useSideMenuBadgeUpdate();
    const onClickHandler = (id, title, idPath, titlePath) => {
        console.log(id, title, idPath, titlePath);
        updateBadge(id, 0);
    }

    return (
        <FullPage
            sideMenu={<SideMenu
                    title="侧边菜单测试系统"
                    logo="/logo.png"
                    hClick = {()=>{console.log("headerOnClick")}}
                    mClick={onClickHandler} />
                }
            pageHeader={
                <Stack
                    direction="row"
                    justifyContent="space-between"
                    alignItems="center"
                    spacing={2}
                    className='w-100'
                >
                    <SToggleButton icon={<VerticalSplitIcon />} />

                    <ToggleThemeButton />
                </Stack>
            }
        >
            <Box className="w-100 h-100 d-flex flex-grow-1 justify-content-center align-items-center">
                <Typography variant='h1'>欢迎来到码蚁基地</Typography>
            </Box>
        </FullPage>
    )
}

export default SideMenuTest;

上面有个按钮组件是切换 Theme 模式的,<ToggleThemeButton/>的功能很简单,就是调用我们先前设计好的 Theme 中的Hook, 这里给出一个示例,供参考。我们在 STheme目录下创建这个组件文件:ToggleThemeButton.jsx

// STheme/TaggleThemeButton.jsx

import IconButton from '@mui/material/IconButton';
import useToggleTheme from "./useToggleThemeHook";
import { useTheme } from '@emotion/react';
import Brightness4Icon from '@mui/icons-material/Brightness4';
import Brightness7Icon from '@mui/icons-material/Brightness7';

function ToggleThemeButton() {
    const toggleSTheme = useToggleTheme();
    const theme = useTheme();

    return (
        <IconButton sx={{ ml: 1 }} onClick={() => { toggleSTheme(); }} color="inherit">
            {theme.palette.mode === 'dark' ? <Brightness7Icon /> : <Brightness4Icon />}
        </IconButton>
    )
}

export default ToggleThemeButton;

是不是很简单。

现在我们在SMenu项目目录下的 App.jsx中引入这个 SideMenuTest 组件就OK 了。如下所示:

import SideMenuTest from "./SideMenuTest";
import SideMenuProvider from "./SMenu/SideMenuProvider";
import sideMenuConfigData from "./menuData";

function App() {
    return (
        <SideMenuProvider menuData={sideMenuConfigData}>
            <SideMenuTest />
        </SideMenuProvider>
    )
}

export default App;

现在的目录结构看起来应该是这个样子的:

在这里插入图片描述

你现在运行以后就可以看到一开始所示的动图的效果了。为了查看Badge的效果,我们在 SideMenuProvider中将Badge的初始化值更改一下。这里改成了 30 ,如下所示:

/**
 * 获取菜单项的id集合, 用于初始化菜单项的徽章,本菜单的每个Item都有一个id属性,用于唯一标识菜单项。
 * @param menuConfig 
 * @returns 
 */
function initBadge(menuConfig){
    let ids = {};
    menuConfig.forEach((element) => {
        const name = element.id;
        ids = { ...ids, [name]: 30 };

        if (element.children) {
            const children = element.children;
            children.forEach(el => {
                const subName = el.id;
                ids = { ...ids, [subName]: 30 };
            })
        }
    });

    return ids;
}

注意,我在 SideMenuTest 中传入菜单项点击事件的回调中 是这样写的:

const updateBadge = useSideMenuBadgeUpdate();
const onClickHandler = (id, title, idPath, titlePath) => {
      console.log(id, title, idPath, titlePath);
      updateBadge(id, 0); // 单击菜单项后清除 消息提示。 
  }

现在的效果应该是这样的:

在这里插入图片描述

现在我们已经验证了菜单的功能 ,但是让菜单和路由结合起来才是我们真正的目的。

设计路由界面

根据我之前 React Router相关的内容知识,我们来要准备一个WellCome页面,一个 Page404 页面, 还有一个无数据匹配的空页面。

在App.jsx 文件中,我们做出如下更改和配置:

import SideMenuTest from "./SideMenuTest";
import SideMenuProvider from "./SMenu/SideMenuProvider";
import sideMenuConfigData from "./menuData";
import Typography from '@mui/material/Typography';

import {
    createBrowserRouter,
    RouterProvider,
} from "react-router-dom";
import Page404 from "./SPages/Page404";
import Wellcome from "./SPages/Wellcome";
import NoMatchRoute from "./SPages/NoMatchRoute";

const router = createBrowserRouter([
    {
        path: "/",
        element: <SideMenuTest />,
        errorElement: <Page404 />,
        children: [
            {
                path: "userCenter",
                element: <Typography variant='h1'>这是个人中心页面模块</Typography>,
            },

            {
                index: true,
                element: <Wellcome />
            },

            {
                path: "*",
                element: <NoMatchRoute />
            }
        ]
    },
]);

function App() {
    return (
        <SideMenuProvider menuData={sideMenuConfigData}>
            <RouterProvider router={router} />
        </SideMenuProvider>
    )
}

export default App;

我们配置了 Index 路由, 还配置了 * 路由,这个路由是当前路径下子路由没有匹配项时就显示这个路由页面。这几个页面我们可以随便写个组件都行,就像 上面配置 userCenter 中的 element 一样。但是为了美观,我事先设计 了几个页面直接引用也是一样的。

现在路由配置好了,那么我们就要在 SideMenuTest中做一点小小的更改,把主页面展示区改成 Router 的占位符组件, 并配置点击事件。如下所示:

import VerticalSplitIcon from '@mui/icons-material/VerticalSplit';
import Box from '@mui/material/Box';
import SideMenu from "./SMenu/SideMenu";
import SToggleButton from './SMenu/_SToggleButton';
import { useSideMenuBadgeUpdate } from './SMenu/_SMenuHooks';
import FullPage from './SLayout/FullPage';
import Stack from '@mui/material/Stack';
import ToggleThemeButton from './STheme/TaggleThemeButton';
import { Outlet, useNavigate } from 'react-router-dom';

function SideMenuTest() {
    const navigate = useNavigate();
    const updateBadge = useSideMenuBadgeUpdate();
    const onClickHandler = (id, title, idPath, titlePath) => {
        console.log(id, title, idPath, titlePath);
        updateBadge(id, 0);
        navigate(idPath.join("/"), true);
    }

    return (
        <FullPage
            sideMenu={<SideMenu
                    title="侧边菜单测试系统"
                    logo="/logo.png"
                hClick={() => { navigate("/", true); }}
                    mClick={onClickHandler} />
                }
            pageHeader={
                <Stack
                    direction="row"
                    justifyContent="space-between"
                    alignItems="center"
                    spacing={2}
                    className='w-100'
                >
                    <SToggleButton icon={<VerticalSplitIcon />} />

                    <ToggleThemeButton />
                </Stack>
            }
        >
            <Box className="w-100 h-100 d-flex flex-grow-1 justify-content-center align-items-center">
                <Outlet />
            </Box>
        </FullPage>
    )
}

export default SideMenuTest;

现在我们的效果应该是这样的:

在这里插入图片描述

相当的完美是不是。 至此,你只要多加练习,就一定能熟练的掌握 React 。本教程到此全部结束。

关于我的计划

快要过年了,事比较多,时间实在抽不出来了。可能要停更好几天了。后面我会出一个系列的 Swift UI 的教程和PHP相关的教程。祝大家新年快乐,万事如意。

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

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

相关文章

解放网工双手-SNMP如何做好运维辅助?

1. SNMP为什么被誉为“网管神器”&#xff1f; 2. SNMP不同版本有何区别&#xff1f; 3. SNMP有哪些问题及Telemetry有何优势&#xff1f; ---- SNMP ----- 简单网络管理协议 U2000&#xff1a;传输设备管理 企业&#xff0c;银行 esight&#xff1a;华为 iMaster NCE-Camp…

【webpack】技巧使用

webpack和TypeScript 安装webpack相关内容安装TS相关内容配置初始化数据初始化运行展示和目录展示报错解决&#xff08;缺失文件配置&#xff09; 安装前端必备神奇lodash测试一下entry配置index.html模板配置修改打包出来的index.html的titleinject注入chunks 属性多页面配置 …

从 20 多套 MySQL 到 1 套 TiDB丨骏伯网络综合运营管理平台应用实践

原文来源&#xff1a; https://tidb.net/blog/a38c72a4 本文作者&#xff1a;骏伯网络 唐帆&#xff0c;PingCAP 贺美存 骏伯网络简介 广州骏伯网络是一家以数据驱动的科技公司&#xff0c;聚焦移动互联网营销服务&#xff0c;坚持以客户为中心&#xff0c;深耕 APP、运营…

大数据学习之Redis,十大数据类型的具体应用(四)

3.8 Redis基数统计&#xff08;HyperLogLog&#xff09; 需求 统计某个网站的UV、统计某个文章的UV 什么是UV unique Visitor &#xff0c;独立访客&#xff0c;一般理解为客户端IP 大规模的防止作弊&#xff0c;需要去重复统计独立访客 比如IP同样就认为是同一个客户 需要去…

sqli.labs靶场(29到40关)

29、第二十九关 id1 id1 尝试发现是单引号闭合&#xff0c; -1 union select 1,2,3-- -1 union select 1,2,database()-- -1 union select 1,2,(select group_concat(table_name) from information_schema.tables where table_schemasecurity)-- -1 union select 1,2,(select…

国内最全的Spring Boot系列之七

• 阿里巴巴前高级研发工程师 • 三家千万级互联网企业技术顾问 • MBTI/盖洛普技术专家 • 厦门某高校外聘教师 • 51CTO特约合作讲师 • 网易云课堂签约讲师 •《深入理解设计模式》作者 一转眼马上要过年了&#xff0c;回首2023年&#xff0c;感觉自己无所事事、碌碌无…

python爬虫5

1.selenium交互 无页面浏览器速度更快 #配置好的自己不用管 from selenium import webdriverfrom selenium.webdriver.chrome.options import Optionschrome_options Options()chrome_options.add_argument(‐‐headless)chrome_options.add_argument(‐‐disable‐gpu)# path…

编程效率的跃升之路

编程是一门需要大量的时间和精力投入的技能&#xff0c;提高编程效率则是一个需要不断学习和实践的过程。结合笔者写bug多年的经验&#xff0c;一些学习建议和资源和大家share下。 一、编程如何提效&#xff1a; 熟悉开发工具&#xff1a;掌握常用的开发工具&#xff0c;如集…

flutter抓包绕过

lutter的证书校验 起因&#xff1a; 最近工作上让做个app的复测&#xff0c;把apk发我后&#xff0c;开始尝试挂代理抓包&#xff0c;结果发现抓不到 为是证书没弄好&#xff0c;想着前几天不是刚导入了吗&#xff08;雾&#xff09;。又重新导入了下还是不行。然后各种lsp模…

OJ_找位置

题干 代码 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<vector> #include<algorithm> #include<map> using namespace std;int main() {char str[200] { 0 };scanf("%s", str);map<char, vector<int>> times…

ROS入门之通信机制及常用API

文章目录 前言一、话题通信1.话题通信理论2.话题通信常用API&#x1f357;发布者advertisepublish &#x1f356;订阅者subscribe 3.自定义msg 二、服务通信1.服务通信理论2.服务通信常用API&#x1f386;服务端advertiseService &#x1f387;客户端serviceClientros::service…

[大厂实践] Pinterest通用计算平台实践

Pinterest平台团队开发实现了名为PinCompute的高性能通用计算平台&#xff0c;支持Pinterest的大量异构用例和服务。本文介绍了团队在开发这一平台过程中的经验和实践&#xff0c;对于其他平台团队来说&#xff0c;具有很好的参考意义。原文: PinCompute: A Kubernetes Backed …

RabbitMQ面试必备:基本概念、组件原理、消息传递模型,一网打尽。解密高可用性、负载均衡,深入了解安全性配置和性能优化

一、RabbitMQ的基本概念&#xff1a; 1.什么是消息队列&#xff1f; 消息队列是一种在分布式系统中用于在不同组件之间传递消息的通信机制。它允许应用程序和服务通过异步方式进行通信&#xff0c;提高了系统的可伸缩性和松耦合性。消息队列通常包括生产者&#xff08;Produc…

node-sass版本与NodeJS版本不匹配的问题

npm install 报错如下 npm ERR! code 1 npm ERR! path D:\Project\git_Product\YYYY\user\node_modules\node-sass npm ERR! command failed npm ERR! command C:\WINDOWS\system32\cmd.exe /d /s /c node scripts/build.js 问题原因 node-sass 与 node 版本不匹配 卸载Node…

PM圆桌派:同事不愿意告诉你的职场套路有哪些?

职场是社会的缩影&#xff0c;想要崭露头角&#xff0c;获得更多升职加薪的机会&#xff0c;就不要做着和多数人一样的事情&#xff0c;却期待着不一样的结果。 职场上有很多潜在的规则&#xff0c;要会做事&#xff0c;也要会说话&#xff0c;更要会做人。如果不懂规则&#…

day43_jdbc

今日内容 0 复习昨日 1 SQL注入问题 2 PreparedStatement 3 完成CRUD练习 4 ORM 5 DBUtil (properties) 6 事务操作 0 复习昨日 已经找人提问… 1 SQL注入 1.1 什么是SQL注入 用户输入的数据中有SQL关键词,导致在执行SQL语句时出现一些不正常的情况.这就是SQL注入! 出现SQL注入…

springcloud-gateway升级版本allowedOrigins要改allowedOriginPatterns

前言 报错: java.lang.IllegalArgumentException: When allowCredentials is true,allowedOrigins cannot contain the special value "*"since that cannot be set on the "Access-Control-Allow-Origin"response header. To allow credentials to a se…

AI大模型专题:OWASP大语言模型应用程序十大风险V1.0

今天分享的是AI大模型系列深度研究报告&#xff1a;《AI大模型专题&#xff1a;OWASP大语言模型应用程序十大风险V1.0》。 &#xff08;报告出品方&#xff1a;OWASP&#xff09; 报告共计&#xff1a;14页 LM01:2023_ 提示词注入 描述&#xff1a;提示词注入包括绕过过滤器…

【Linux】解决:为什么重复创建同一个【进程pid会变化,而ppid父进程id不变?】

前言 大家好吖&#xff0c;欢迎来到 YY 滴Linux 系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过Linux的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; YY的《C》专栏YY的《C11》专栏YY的…

Java八大常用排序算法

1冒泡排序 对于冒泡排序相信我们都比较熟悉了&#xff0c;其核心思想就是相邻元素两两比较&#xff0c;把较大的元素放到后面&#xff0c;在一轮比较完成之后&#xff0c;最大的元素就位于最后一个位置了&#xff0c;就好像是气泡&#xff0c;慢慢的浮出了水面一样 Jave 实现 …