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

今天我们来用所学的知识来做一个布局菜单的组件, 针对这个组件我之前写过一个教程 React之布局菜单-CSDN博客,那个呢比较基础,这节课算是对那个教程的一个扩展和补充。这个实例讲完,这个系列就算告一段落了。先看效果在这里插入图片描述
这个教程要求对React知识的了解要求比较全面,如果你是跟着我这个系统文章一路学来的,应该就能跟得上学习进度。本教程内容很多,很详细,会分为几个章节来讲解。

安装

首先要安装MUI React RouterReact Redux这是必不可少的。我们除了会完成在开头的动图效果示例之外,还有较完整功能添加,所以,会用到一些没有讲过的功能。

设计前的考虑
  • 为了考虑到高度自定义这个特性,我们把菜单的配置以 json数组的形式进行配置。你可以把菜单配置放在服务器上,基于权限的考虑你甚至可以在后台根据用户权限的不同返回不同的菜单配置,实现角色的功能 。
  • 我们尽可能的将与业务代码无关的东西封装在组件内部,这样调用起来代码就很简洁。
  • 根据业务逻辑尽可能的细小化、模块化。
  • 所有UI元素都要适配暗黑模式,也就是两种颜色模式。
Bootstrap

前端是绕不开Css的,但是对于一个完整的项目来说,写Css就很繁琐,我的主张是,能偷懒就偷懒,不能偷懒想办法偷懒。这不,对于布局中的GridFlex 方面,Bootstrap 就提供了相当完美的功能了,我认为这方面它比MUI强许多,既然如此,何不做个拿来主义者呢,何苦自己为难自己呢。书回正传,回到我们的项目,在源目录(src) 下新建一个本章的实例目录:SMenu , 并在这个目录下新建目录 SCSS, 我们把网上下载的Bootstrap5.3的Css文件放到这个目录里。另外,我也提供了两个其它的两个css文件,目录结构如下所示:

在这里插入图片描述

关于Bootstrap的样式,请大家自行学习,此处不做详解。

以下是 components.css 的内容

.fade-enter {opacity: 0;transform: translateX(-100%);}.fade-enter-active {opacity: 1;transform: translateX(0%);}.fade-exit {opacity: 1;transform: translateX(0%);}.fade-exit-active {opacity: 0;transform: translateX(100%);}.fade-enter-active,.fade-exit-active {transition: opacity 500ms, transform 500ms;}.my-node-enter {opacity: 0;}.my-node-enter-active {opacity: 1;transition: opacity 200ms;}.my-node-exit {opacity: 1;}.my-node-exit-active {opacity: 0;transition: opacity 200ms;}/**弹窗动画*/.speedx-alert-enter {opacity: 0;transform: scale(0.9);}.speedx-alert-enter-active {opacity: 1;transform: translateX(0);transition: opacity 300ms, transform 300ms;}.speedx-alert-exit {opacity: 1;}.speedx-alert-exit-active {opacity: 0;transform: scale(0.9);transition: opacity 300ms, transform 300ms;}

下面是public.css的内容

html {background-color:#f2f2f2;
}body {margin: 0;font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen','Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',sans-serif;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;font-size: 18px;line-height: 1.667;color: #222;text-align: justify;word-wrap: break-word;word-break: break-word;-moz-hyphens: auto;hyphens: auto;
}input,
textarea {font-family: 'Roboto', sans-serif;line-height: 1.4;background: #eee;
}code {font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace;color: #353535d9;overflow-wrap: break-word;
}:not(pre) > code {background-color: rgb(214, 214, 214);border-radius: 3px;padding: 1px 3px;
}img {max-width: 100%;max-height: 20em;
}.page-container {position: relative;display: flex;flex-direction: column;background-color:white;min-height: 100vh;
}.layout-content{margin: 10px, 0px;padding: 0px;min-height: 100%;flex: 1;text-align:justify;
}.content-wrap {padding-bottom: 2.5rem;    /* Footer height */
}.footer {position: absolute;bottom: 0;width: 100%;height: 2.5rem;            /* Footer height */padding: 20px 0;/* box-shadow: 3px 0 5px #c9c9c9; */
}blockquote {border-left: 2px solid rgb(1, 154, 192);margin-left: 0;margin-right: 0;padding-left: 10px;color: rgb(150, 150, 150);font-style: italic;
}blockquote[dir='rtl'] {border-left: none;padding-left: 0;padding-right: 10px;border-right: 2px solid #ddd;
}input {box-sizing: border-box;font-size: 0.85em;width: 100%;padding: 0.5em;border: 2px solid #ddd;background: #fafafa;
}input:focus {outline: 0;border-color: blue;
}iframe {width: 100%;border: 1px solid #eee;
}[data-slate-editor] > * + * {margin-top: 1em;
}#root{display: flex;min-height: 100vh;flex-direction: column;background-color:#f2f2f2;
} .alignCenterVH{position: relative;top: 50%;transform: translateY(-50%);text-align: center;
}.mainBoxPosition{flex: 1;display: flex;justify-content: center;align-items: top;
}.titleInput {display: block;width: 100%;font-weight: bold;min-height: 50px;font-size: 22px;border:none;border-bottom: 1px;border-color: rgb(190, 190, 190);outline:none;
}.selectElement {display: block;max-width: 100%;max-height: 20em;
}.imgsubstring {display: block;color:rgb(116, 116, 116);font-weight: 500;font-size: medium;padding: 5px;text-align: center;
}.mayi-select {width: 400px; height: 200px;line-height: 200px;text-align: center;margin:auto;border: 1px solid #ccc;background: linear-gradient(#efefef,#ccc) padding-box,linear-gradient(135deg, rgba(0, 0, 0, 1) 25%, transparent 25%, transparent 50%, rgba(1, 1, 1, 1) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);background-size:100% 100%, 8px 8px;animation: bg 1s linear infinite;
}.mayi-select:hover{cursor: pointer;border: 1px dashed transparent;
}@keyframes bg {0% {background-position: 0 0;}100% {background-position: 8px 0;}
} .alignCenter {display: table-cell;/*垂直居中 */vertical-align: middle;/*水平居中*/text-align: center;/* text-align: center;background-color: #fff;position: absolute;left: 50%;top: 50%;transform: translate(-50%,-50%); */
}.site-layout-background{background-color: white;
}.check-background {width: 100px;height: 100px;background-image: url('data:image/svg+xml,\<svg xmlns="http://www.w3.org/2000/svg"\width="100" height="100" fill-opacity=".25">\<rect x="50" width="50" height="50"></rect>\<rect y="50" width="50" height="50"></rect>\</svg>');background-size:50px 50px;
}

设计一个样式组件,在App中引入一下就可以了,就可以保证我们的所有组件就能够应用到我们的样式。在STheme文件夹中创建 AdapterCss.jsx

import CssBaseline from '@mui/material/CssBaseline';
import '../SCSS/public.css';
import '../SCSS/components.css';
import '../SCSS/bootstrap5.3.0/bootstrap-utilities.min.css';
import '../SCSS/bootstrap5.3.0/bootstrap-grid.min.css';
// import '../SCSS/bootstrap5.3.0/bootstrap.min.css';export default function AdapterCss() {return <CssBaseline />
}

我们只要在根组件中引入一次这个样式适配器就好了。

颜色模式

因为我们要为App适配暗模式,所以在设计之初就要考虑好这个问题。首先,MUI所有的组件就已经适配了两种颜色模式,Bootstrap也是一样。还有一个就是我们自己封装的组件也要适配到暗模式中,就这要求我们自己设计的组件元素应用的颜色模式要么来处MUI, 要么采用Bootstrap,要么我们自己提供一个双模式的颜色体系。也就是说这三种不同框架之间的颜色体系是共存的。下面我们分别来说一说:

MUI的Theme模式

MUI 中提供了两个工具,让我们能构获取和设置颜色模式。

  • ThemeProvider 这个很好理解,就是一个颜色模式厂,就是一个Context;
  • createTheme 创建一个颜色模式。我们这里只是用它来改变MUI的颜色模式;

下面我们用示例说明用法:

import { createTheme } from '@mui/material/styles';function createMuiTheme(mode) {const themeMode = mode === "light" ? "light" : "dark";return createTheme({palette: {mode: themeMode,},});
}

上面的函数根据我们传入的模式关键字来创建相应的MUI颜色模式。

Bootstrap的颜色模式

这就简单了,我们只要改变顶层包裹组件的data-bs-theme属性值就可以切换颜色模式。

<div data-bs-theme="light"> 这是 light 模式 <div><div data-bs-theme="dark"> 这是 dark 模式 <div>

很简单吧。

自定义颜色模式

自定义颜色模式就有点技术含量了。也是最繁琐的一环。首先我们要定义的每种颜色要有两个模式下的颜色值。这就要一个标准,由于我没有采用 TS 设计模式,所以就要用其它的办法来约束定义的行为,比如一个函数就是一个很好的办法。

我们在STheme目录中创建一个工具函数库,把所有的我们自定义的工具函数放到其中统一导出就好了。

// SThemeUtils.jsximport SThemeCodors from "./SColors";// 生成基本颜色,lightColor为浅色,darkColor为深色
export function sColor(lightColor, darkColor) {return {light: lightColor,dark: darkColor,}
}/*** 生成主题模型* @param {} mode * @returns */
export default function createSTheme(mode = "light") {const themeMode = mode === "light" ? "light" : "dark";const sTheme = {mode: themeMode};Object.keys(SThemeCodors).forEach(key => {sTheme[key] = SThemeCodors[key][themeMode];});return sTheme;
}/*** 生成MUI系统主题* @param {*} mode * @returns */
export function createMuiTheme(mode) {const themeMode = mode === "light" ? "light" : "dark";return createTheme({palette: {mode: themeMode,},});
}
  • 我们通过sColor函数生成一个颜色对象,这样行为就统一了。每个颜色对象中都有一个 light 色 和一个 dark 色。所以我们设计之初就要把每种不同模式下的颜色配置好。这关系到我们整体的App风格。你看,我们设计一个App其实没那么简单对不对,对不同技术技能都要些要求的。
  • createSTheme根据自定义颜色模式生成基于自定义颜色的 theme`

现在就是定义颜色了,在相同的目录下,创建颜色库文件

// sColors.jsximport { sColor } from "./SThemeUtils";/*** 定义主题颜色模型*/
const SThemeColors = {bgColor: sColor("#edf3f2", "#1D1D1D"), //背景色/*** 菜单色配置*/badge: sColor("red", "red"), //小红点色menuBgcolor: sColor("#EEEEEE", "#0D2745"),//菜单栏的背景色hoverMenuBgcolor: sColor("#FFEACC", "#091C32"), //菜单栏背景色HovericonColorNormal: sColor("#1c2322", "#EEEEEE"), //图标色iconColorSquare: sColor("#363c3b", "#CCCCCC"), //无图标时的替代色menuNomalColor: sColor("#333333", "#07172A"), //菜单栏正常字体色activeMenuBgcolor: sColor("#FFEACC", "#1C54AD"), //活动菜单背景色activeBorderColor: sColor("#007AFF", "#1C54AD"), //活动菜单边框色menuSpliderColor: sColor("#DDDDDD", "#143C6A"), // 菜单栏分隔色menuSubitemColor: sColor("#545a59", "#B8B8B8"), //子菜单字体色hoverSubitemColor: sColor("#9fa2a1", "#3C628B"), //hover时的子菜单字体色hoverMenuSubitemBgcolor: sColor("#FFEACC", "#123862"), //子菜单的hover背景色activeMenuSubitemBgcolor: sColor("#FFBF66", "#0E2C4D"),//活动子菜单的背景色activeQuickMenuBgcolor: sColor("#FFBF66", "#2266B5"),//活动快捷菜单的子菜单
}export default SThemeColors;

这就是我们的颜色系统,根据需要自行定义。

创建 ThemeProvider

现在我们向App提供三种 provider, 还要提供 切换 模式的方法,最好的办法当然就是 Context了,我们来设计这几个Provider : 创建 SThemeContext.jsx文件:

// SThemeContext.jsximport { createContext } from 'react';/*** 创建自定义主题上下文*/
export const SThemeContext = createContext(null);export function CusThemeProvider({ theme, children }) {return (<SThemeContext.Provider value={theme}>{children}</SThemeContext.Provider>)
}/*** 创建切换主题上下文*/
export const ToggleSThemeContext = createContext(null);export function ToggleSThemeProvider({ handler, children }) {return (<ToggleSThemeContext.Provider value={handler}>{children}</ToggleSThemeContext.Provider>)
}/*** 创建Bootstrap主题上下文* @param {*} param0 * @returns */
export function BootstrapThemeProvider({ mode, children }) {return (<div data-bs-theme={mode}>{children}</div>)
}

文件里已经备注的很清楚了,就是创建两个上下文就OK了。

现在三种颜色的框架都有了。接下来我们就是要把这三个模式合并成一个Provider就完美了。我们来创建这个文件。在STheme目录下创建 SThemeProvider.jsx文件

// SThemeProvider.jsximport { useState } from 'react';
import { ThemeProvider } from '@mui/material/styles';
import AdapterCss from './AdapterCss';
import createSTheme, { createMuiTheme } from './SThemeUtils';
import { BootstrapThemeProvider, CusThemeProvider, ToggleSThemeProvider} from './SThemeContext';/*** 项目的皮肤供应器* @param {} param0 * @returns */
function SThemeProvider({ children }) {  const [theme, changeTheme] = useState({ custom: createSTheme("light"), muiTheme: createMuiTheme("light")});const toggleThemHandler = () => {const muiThemeMode = theme.muiTheme.palette.mode === "light" ? "dark" : "light";changeTheme({custom: createSTheme(muiThemeMode),muiTheme: createMuiTheme(muiThemeMode),})}return (<ThemeProvider theme={theme.muiTheme}><CusThemeProvider theme={theme.custom}><BootstrapThemeProvider mode={theme.custom.mode}><ToggleSThemeProvider handler={toggleThemHandler}><AdapterCss />{children}</ToggleSThemeProvider></BootstrapThemeProvider></CusThemeProvider></ThemeProvider>)
}export default SThemeProvider;

现在层次很清晰了吧。是不是清爽了许我,这样,我们在根组件中用 SThemeProvider包裹就好了。是不是很优雅。我们只需要在项目入口文件 main.jsx 中这样写就行了。

import React from 'react'
import ReactDOM from 'react-dom/client'
import SThemeProvider from './SMenu/STheme/SThemeProvider.jsx';
import App from './SMenu/App.jsx';ReactDOM.createRoot(document.getElementById('root')).render(<React.StrictMode><SThemeProvider><App /></SThemeProvider></React.StrictMode>,
)
编写主题切换Hook

这是主题最后一个环节,我们要提供一个 Hook 供我们的组件使用,要不然,设计主题有什么意义呢。

在 STheme目录中创建 文件 useToggleThemeHook.jsx

import { useContext } from 'react';
import { ToggleSThemeContext } from './SThemeContext';// 获取切换主题的功能函数。
const useToggleTheme = () => {return useContext(ToggleSThemeContext)
}export default useToggleTheme;

是不是太完美了。 是相当的完美啊。(未完待续)

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

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

相关文章

算法学习——华为机考题库6(HJ36 - HJ40)

算法学习——华为机考题库6&#xff08;HJ36 - HJ40&#xff09; HJ36 字符串加密 描述 有一种技巧可以对数据进行加密&#xff0c;它使用一个单词作为它的密匙。下面是它的工作原理&#xff1a;首先&#xff0c;选择一个单词作为密匙&#xff0c;如TRAILBLAZERS。如果单词中…

DDD技术方案落地实践

DDD技术方案落地实践 引言 从接触领域驱动设计的初学阶段&#xff0c;到实现一个旧系统改造到DDD模型&#xff0c;再到按DDD规范落地的3个的项目。对于领域驱动模型设计研发&#xff0c;从开始的各种疑惑到吸收各种先进的理念&#xff0c;目前在技术实施这一块已经基本比较成…

Postgres与DynamoDB:选择哪个数据库

启动新项目时需要做出的决定之一是使用哪个数据库。如果您使用的是Django这样的包含电池的框架&#xff0c;那么没有理由再三考虑。选择一个受支持的数据库引擎&#xff0c;就可以了。另一方面&#xff0c;如果你使用像FastAPI或Flask这样的微框架&#xff0c;你需要自己做出这…

JVM系列——垃圾收集器Parrlel Scavenge、CMS、G1常用参数和使用场景

背景 当前在Java领域&#xff0c;JDK 8版本仍然享有广泛的使用&#xff0c;它支持了Parallel Scavenge、CMS和G1这几种垃圾收集器。因此&#xff0c;为了在业务应用中更加高效地进行开发和性能调优&#xff0c;我们需要对这些垃圾收集器的工作原理和特性有一个全面的理解和认识…

【MySQL】双写、重做日志对宕机时脏页数据落盘的作用的疑问及浅析

众所周知&#xff0c;双写机制、重做日志文件是mysql的InnoDB引擎的几个重要特性之二。其中两者的作用都是什么&#xff0c;很多文章都有分析&#xff0c;如&#xff0c;双写机制&#xff08;Double Write&#xff09;是mysql在crash后恢复的机制&#xff0c;而重做日志文件&am…

【复现】大华 DSS 数字监控系统 任意文件读取漏洞_38

目录 一.概述 二 .漏洞影响 三.漏洞复现 1. 漏洞一&#xff1a; 四.修复建议&#xff1a; 五. 搜索语法&#xff1a; 六.免责声明 一.概述 大华DSS是大华的大型监控管理应用平台&#xff0c;支持几乎所有涉及监控等方面的操作&#xff0c;支持多级跨平台联网等操作。 可…

2024年适合进入股市吗?北京想开股票账户找哪家证券公司交易佣金费用最低?

股市规则是指股票市场中的一系列规则和制度&#xff0c;用于监管和管理股票交易。以下是一些常见的股市规则&#xff1a; 证券法律法规&#xff1a;股市规则的基础是国家的证券法律法规&#xff0c;包括证券法、公司法等&#xff0c;用于规范股票发行、交易和上市等方面的法律规…

重生奇迹MU套装怎么配

汉斯的皮套装&#xff1a;冰之指环,皮护腿,皮盔,皮护手,皮靴,皮铠,流星槌 汉斯的青铜套装&#xff1a;青铜护腿,青铜靴,青铜铠 汉斯的翡翠套装&#xff1a;雷之项链,翡翠护腿,翡翠盔,翡翠铠,远古之盾 汉斯的黄金套装&#xff1a;火之项链,黄金护腿,黄金护手,黄金靴,黄金铠 …

代码随想录算法训练营DAY11 | 栈与队列 (2)

一、LeetCode 20 有效的括号 题目链接&#xff1a;20.有效的括号https://leetcode.cn/problems/valid-parentheses/ 思路&#xff1a;遇到左括号直接进栈&#xff1b;遇到右括号判断站顶是否有匹配的括号&#xff0c;没有就返回flase&#xff0c;有就将栈顶元素出栈&#xff1…

FANUC机器人示教器的菜单变成了图标,如何改成列表的形式?

FANUC机器人示教器的菜单变成了图标&#xff0c;如何改成列表的形式&#xff1f; 如下图所示&#xff0c;开机后按下MENU菜单键时&#xff0c;发现原来的列表形式变成了菜单图标的形式&#xff0c;同时在按F1-F5键时&#xff0c;提示&#xff1a;HMI模式-键不可用&#xff0c; …

向日葵案例解析:无外网接入,医疗设备如何进行远程售后运维

随着医学科学以及生物工程技术的高速发展&#xff0c;医院对于高端医疗设备如MR、CT、B超等高科技成像设备和放射治疗设备的需求激增。医学影像检查作为一种重要的手段&#xff0c;在许多疾病确诊过程中发挥着至关重要的作用。检查结果正确与否&#xff0c;直接影响临床医生对疾…

JS 引导动画

前言 引导动画是程序在某一时刻播放的动画&#xff0c;通常用于向用户介绍程序的功能和特点。 实现效果 实现方式 引导动画的实现方式有很多种&#xff0c;这里我使用的是 CSS 的 clip-path 属性。 技术选型 这里我为什么要选择 clip-path 属性而不是 mask 属性呢&#xf…

阿狸与小兔子的奇幻之旅

在很久很久以前&#xff0c;有一个遥远的国度&#xff0c;这个国度里生活着各种各样的动物&#xff0c;它们和谐共处&#xff0c;幸福快乐。在这个国度里&#xff0c;有一只聪明伶俐的小狐狸&#xff0c;名叫阿狸。 一天&#xff0c;阿狸在森林里散步时&#xff0c;遇到了一只正…

关于网络面试题汇总

什么是TCP/IP五层模型&#xff1f;它们的作用是啥&#xff1f;基于TCP/IP实现的应用&#xff08;层协议&#xff09;有哪些&#xff1f; TCP/IP五层模型&#xff0c;从上向下分别是&#xff1a; 应用层&#xff1a;应用程序本身&#xff0c;应用层的作用是负责应用程序之间的…

数据结构篇-05:哈希表解决字母异位词分组

本文对应力扣高频100 ——49、字母异位词分组 哈希表最大的特点就是它可以把搜索元素的时间复杂度降到O(1)。这一题就是要我们找到 “字母异位词” 并把它们放在一起。 “字母异位词”就是同一个单词中字母的不同组合形式。判断“字母异位词”有两个视角&#xff1a;1、所含字…

全面认识DOS系统

目录 一、DOS系统的功能 1.执行命令和程序&#xff08;处理器管理&#xff09; 2.内存管理 3.设备管理 4.文件管理 5.作业管理 二、文件与目录 三、文件类型与属性 1.系统属性&#xff08;S&#xff09; 2.隐含属性&#xff08;H&#xff09; 3.只读属性&#xff08…

初谈类和对象

文章目录 前言类的引入类的定义类的两种定义方式成员命名规则 类的访问限定符及封装访问限定符面试题封装 类的作用域类的实例化类对象模型计算类对象的大小 this指针this指针特性 前言 C语言是面向过程的&#xff0c;关注点是过程&#xff1b;而C面向的是对象&#xff0c;关注…

mysql-FIND_IN_SET查询优化

优化前 SELECTuser_id,user_name,real_name,PASSWORD,real_org_id,real_org_name,real_dept_id,real_dept_name, STATUS FROMsys_user WHEREis_del 0 AND find_in_set( lilong, login_user_account ) 优化后 SELECTuser_id,user_name,real_name,PASSWORD,real_org_id,real…

回归预测 | Matlab实现RIME-CNN-LSTM-Attention霜冰优化卷积长短期记忆网络注意力多变量回归预测(SE注意力机制)

回归预测 | Matlab实现RIME-CNN-LSTM-Attention霜冰优化卷积长短期记忆网络注意力多变量回归预测&#xff08;SE注意力机制&#xff09; 目录 回归预测 | Matlab实现RIME-CNN-LSTM-Attention霜冰优化卷积长短期记忆网络注意力多变量回归预测&#xff08;SE注意力机制&#xff0…

如何处理我们的文本数据成构建词表

我们拿到在拿到一堆语料数据&#xff0c;或者是在网络中爬取下来的文本数据如何处理成为模型能够训练的数据呢&#xff1f;这里有我们先经过停用词和按字分词的处理之后&#xff0c;得到的问答对文本数据&#xff0c;input_by_word.txt 和 target_by_word.txt 。其中&#xff0…