当前位置: 首页 > news >正文

【React】入门Day03 —— Redux 与 React Router 核心概念及应用实例详解

1. Redux 介绍

// 创建一个简单的Redux store
const { createStore } = Redux;// reducer函数
function counterReducer(state = { count: 0 }, action) {switch (action.type) {case 'INCREMENT':return { count: state.count + 1 };case 'DECREMENT':return { count: state.count - 1 };default:return state;}
}// 创建store实例
const store = createStore(counterReducer);// 订阅数据变化
store.subscribe(() => {console.log(store.getState());
});// 触发数据变化
store.dispatch({ type: 'INCREMENT' });
  • 概念

    • 是 React 常用的集中状态管理工具,可独立于框架运行,类似于 Vue 中的 Pinia(Vuex)。
    • 通过集中管理方式管理应用状态。
  • 使用原因

    • 独立于组件,无视层级关系,简化通信。
    • 单向数据流清晰,易于定位 bug。
    • 调试工具配套良好,方便调试。

2. Redux 快速体验

<button id="decrement">-</button>
<span id="count">0</span>
<button id="increment">+</button>
<script src="https://unpkg.com/redux@latest/dist/redux.min.js"></script>
<script>// 定义reducer函数 function counterReducer (state = { count: 0 }, action) {switch (action.type) {case 'INCREMENT':return { count: state.count + 1 }case 'DECREMENT':return { count: state.count - 1 }default:return state}}const store = Redux.createStore(counterReducer);store.subscribe(() => {document.getElementById('count').innerText = store.getState().count;});const inBtn = document.getElementById('increment');inBtn.addEventListener('click', () => {store.dispatch({ type: 'INCREMENT' });});const dBtn = document.getElementById('decrement');dBtn.addEventListener('click', () => {store.dispatch({ type: 'DECREMENT' });});
</script>
  • 计数器实现

    • 定义 reducer 函数,根据 action 返回新状态。
    • 使用 createStore 传入 reducer 生成 store 实例。
    • 用 store 的 subscribe 方法订阅数据变化。
    • 通过 store 的 dispatch 方法提交 action 触发变化。
    • 利用 store 的 getState 方法获取最新状态更新视图。
  • 数据流架构

    // 定义state
    const initialState = { count: 0 };// 定义action
    const incrementAction = { type: 'INCREMENT' };// 定义reducer
    function counterReducer(state = initialState, action) {switch (action.type) {case 'INCREMENT':return { count: state.count + 1 };default:return state;}
    }
    • 包含 state(存放数据对象)、action(描述数据修改对象)、reducer(根据 action 更新 state 的函数)三个核心概念。

3. Redux 与 React

# 创建React项目
npx create-react-app react-redux # 安装配套工具
npm i @reduxjs/toolkit  react-redux # 启动项目
npm run start 
  • 环境准备

    • 安装 Redux Toolkit(RTK)和 react-redux。
    • 使用 CRA 创建 React 项目,安装配套工具并启动。
    • 设计 store 目录结构,包括单独的 store 目录和内部的 modules 目录,入口文件组合子模块并导出 store。
  • 实现 counter

    // counterStore.js
    import { createSlice } from '@reduxjs/toolkit';const counterStore = createSlice({name: 'counter',initialState: { count: 1 },reducers: {increment(state) {state.count++;},decrement(state) {state.count--;}}
    });const { increment, decrement } = counterStore.actions;
    const counterReducer = counterStore.reducer;
    export { increment, decrement };
    export default counterReducer;// store.js
    import { configureStore } from '@reduxjs/toolkit';
    import counterReducer from './modules/counterStore';
    export default configureStore({reducer: {counter: counterReducer}
    });// App.jsx
    import React from 'react';
    import ReactDOM from 'react-dom/client';
    import App from './App';
    import store from './store';
    import { Provider } from 'react-redux';
    ReactDOM.createRoot(document.getElementById('root')).render(<Provider store={store}><App /></Provider>
    );// 在组件中使用store数据
    import { useSelector } from 'react-redux';
    const count = useSelector(state => state.counter.count);// 在组件中修改store数据
    import { useDispatch } from 'react-redux';
    const dispatch = useDispatch();
    dispatch(increment());
    • 使用 React Toolkit 创建 counterStore,定义模块名称、初始数据和修改数据的同步方法。
    • 为 React 注入 store,使用 Provider 组件传递 store 实例。
    • React 组件中用 useSelector 获取 store 数据,用 useDispatch 修改 store 数据。
  • 提交 action 传参

    // reducer函数
    function counterReducer(state = { count: 0 }, action) {switch (action.type) {case 'INCREMENT_WITH_PARAM':return { count: action.payload.targetCount };default:return state;}
    }// 触发action并传递参数
    const targetCount = 10;
    store.dispatch({ type: 'INCREMENT_WITH_PARAM', payload: { targetCount } });
    • 在 reducers 同步修改方法中添加 action 对象参数,调用 actionCreater 时传递参数到 action 对象的 payload 属性。
  • 异步 action 处理

    // channelStore.js
    import { createSlice } from '@reduxjs/toolkit';
    import axios from 'axios';const channelStore = createSlice({name: 'channel',initialState: { channelList: [] },reducers: {setChannelList(state, action) {state.channelList = action.payload;}}
    });const { setChannelList } = channelStore.actions;
    const url = 'http://geek.itheima.net/v1_0/channels';
    const fetchChannelList = () => {return async (dispatch) => {const res = await axios.get(url);dispatch(setChannelList(res.data.data.channels));}
    };
    export { fetchChannelList };
    const channelReducer = channelStore.reducer;
    export default channelReducer;// App.jsx
    import { useEffect } from 'react';
    import { useSelector, useDispatch } from 'react-redux';
    import { fetchChannelList } from './store/channelStore';function App() {const { channelList } = useSelector(state => state.channel);useEffect(() => {dispatch(fetchChannelList());}, [dispatch]);return (<div className="App"><ul>{channelList.map(task => <li key={task.id}>{task.name}</li>)}</ul></div>);
    }
    export default App;
    • 创建 store 配置同步方法,单独封装函数,在新函数中封装异步请求获取数据并调用同步 actionCreater 生成 action 对象提交。

4. Redux 调试

  • 官方提供调试工具,支持实时 state 信息展示和 action 提交信息查看。

5. 路由快速上手

// 假设已有一个简单的React组件结构
import React from 'react';
import ReactDOM from 'react-dom/client';// 定义两个简单组件
const LoginComponent = () => <div>登录页面内容</div>;
const ArticleComponent = () => <div>文章页面内容</div>;// 这里模拟路由配置(实际使用React Router的配置方式会更复杂)
const routes = [{ path: '/login', component: LoginComponent },{ path: '/article', component: ArticleComponent }
];// 根据当前路径渲染相应组件(这里是简化的逻辑,实际需要根据React Router的机制来实现)
const App = () => {const currentPath = window.location.pathname;const ComponentToRender = routes.find(route => route.path === currentPath)?.component || null;return <>{ComponentToRender}</>;
};ReactDOM.createRoot(document.getElementById('root')).render(<App />);
  • 前端路由概念

    • 一个路径对应一个组件,访问路径时对应组件在页面渲染。
  • 开发环境创建

    # 使用CRA创建项目
    npm create-react-app react-router-pro# 安装最新的ReactRouter包
    npm i react-router-dom# 启动项目
    npm run start
    • 使用 CRA 创建项目,安装 React Router 包,启动项目。
  • 快速开始

    import React from 'react';
    import ReactDOM from 'react-dom/client';
    import { createBrowserRouter, RouterProvider } from 'react-router-dom';const router = createBrowserRouter([{path: '/login',element: <div>登录</div>},{path: '/article',element: <div>文章</div>},
    ]);ReactDOM.createRoot(document.getElementById('root')).render(<RouterProvider router={router} />
    );
    • 使用createBrowserRouter创建路由,配置路径和对应组件,通过RouterProvider渲染路由。

6. 抽象路由模块

// 假设这是一个简单的路由模块文件
import { createBrowserRouter, RouterProvider } from 'react-router-dom';// 定义各个路由组件
const HomeComponent = () => <div>首页</div>;
const AboutComponent = () => <div>关于我们</div>;
const ContactComponent = () => <div>联系我们</div>;// 创建路由配置
const router = createBrowserRouter([{path: '/',element: HomeComponent},{path: '/about',element: AboutComponent},{path: '/contact',element: ContactComponent}
]);// 导出路由配置供其他文件使用
export default router;
  • (文档中未详细说明相关内容,可能需要进一步查看实际模块相关代码)

7. 路由导航

  • 概念

    • 路由系统中多个路由间需进行跳转及参数传递通信。
  • 声明式导航

    import React from 'react';
    import { Link } from 'react-router-dom';const NavMenu = () => (<nav><Link to="/home">首页</Link><Link to="/about">关于</Link><Link to="/contact">联系</Link></nav>
    );
    • 通过<Link/>组件,指定to属性为路由路径实现跳转,传参可字符串拼接。
  • 编程式导航

    import React from 'react';
    import { useNavigate } from 'react-router-dom';const LoginButton = () => {const navigate = useNavigate();const handleLogin = () => {// 假设这里是登录逻辑,登录成功后进行跳转navigate('/dashboard');};return <button onClick={handleLogin}>登录</button>;
    };
    • 使用useNavigate钩子获取导航方法,调用navigate方法传入路径实现跳转,更灵活。

8. 导航传参

import React from 'react';
import { useNavigate } from 'react-router-dom';const ProductDetailButton = () => {const navigate = useNavigate();const productId = 123; // 假设这是一个产品IDconst handleNavigate = () => {navigate(`/product/${productId}`);};return <button onClick={handleNavigate}>查看产品详情</button>;
};
  • (文档中未详细说明相关内容,可能需要进一步查看实际传参相关代码)

9. 嵌套路由配置

  • 概念

    • 一级路由中内嵌其他路由为嵌套路由,内嵌的为二级路由。
      import React from 'react';
      import { createBrowserRouter, RouterProvider } from 'react-router-dom';// 定义子路由组件
      const SubPage1 = () => <div>子页面1</div>;
      const SubPage2 = () => <div>子页面2</div>;// 一级路由组件
      const MainPage = () => <div>主页面</div>;// 创建嵌套路由配置
      const router = createBrowserRouter([{path: '/main',element: MainPage,children: [{path: 'sub1',element: SubPage1},{path: 'sub2',element: SubPage2}]}
      ]);ReactDOM.createRoot(document.getElementById('root')).render(<RouterProvider router={router} />
      );
  • 配置步骤

    • 使用children属性配置嵌套关系,用<Outlet/>组件配置二级路由渲染位置。
      import React from 'react';
      import { createBrowserRouter, RouterProvider, Outlet } from 'react-router-dom';// 定义子路由组件
      const SubPage1 = () => <div>子页面1</div>;
      const SubPage2 = () => <div>子页面2</div>;// 一级路由组件
      const MainPage = () => <div>主页面,这里可以放置一些通用的内容,子页面会在Outlet处渲染</div>;// 创建嵌套路由配置
      const router = createBrowserRouter([{path: '/main',element: MainPage,children: [{path: 'sub1',element: SubPage1},{path: 'sub2',element: SubPage2}]}
      ]);ReactDOM.createRoot(document.getElementById('root')).render(<RouterProvider router={router}><MainPage><Outlet /></MainPage></RouterProvider>
      );
  • 默认二级路由

    • 访问一级路由时,二级路由去掉路径,设置index属性为true可默认渲染。
      import React from 'react';
      import { createBrowserRouter, RouterProvider, Outlet } from 'react-router-dom';// 定义子路由组件
      const SubPage = () => <div>默认子页面</div>;// 一级路由组件
      const MainPage = () => <div>主页面,这里可以放置一些通用的内容,子页面会在Outlet处渲染</div>;// 创建嵌套路由配置
      const router = createBrowserRouter([{path: '/main',element: MainPage,children: [{path: '',index: true,element: SubPage}]}
      ]);ReactDOM.createRoot(document.getElementById('root')).render(<RouterProvider router={router}><MainPage><Outlet /></MainPage></RouterProvider>
      );
  • 404 路由配置

    • 准备NotFound组件,在路由表末尾用*作为路径配置路由。
      import React from 'react';
      import { createBrowserRouter, RouterProvider } from 'react-router-dom';
      import NotFoundComponent from './NotFoundComponent';// 其他路由配置
      const router = createBrowserRouter([//...其他路由{path: '*',element: NotFoundComponent}
      ]);ReactDOM.createRoot(document.getElementById('root')).render(<RouterProvider router={router} />
      );
  • 路由模式

    • 常用history模式和hash模式。
      • history模式:url表现为url/login,基于history对象和pushState事件,需后端支持。
        import React from 'react';
        import { createBrowserRouter, RouterProvider } from 'react-router-dom';// 假设后端已正确配置处理history模式的路由请求const router = createBrowserRouter([{path: '/login',element: <div>登录页面内容</div>},{path: '/article',element: <div>文章页面内容</div>}
        ]);ReactDOM.createRoot(document.getElementById('root')).render(<RouterProvider router={router} />
        );
      • hash模式:url表现为url/#/login,监听hashChange事件,无需后端支持。
        import React from 'react';
        import { createHashRouter, RouterProvider } from 'react-router-dom';const router = createHashRouter([{path: '/login',element: <div>登录页面内容</div>},{path: '/article',element: <div>文章页面内容</div>}
        ]);ReactDOM.createRoot(document.getElementById('root')).render(<RouterProvider router={router} />
        );

相关文章:

【React】入门Day03 —— Redux 与 React Router 核心概念及应用实例详解

1. Redux 介绍 // 创建一个简单的Redux store const { createStore } Redux;// reducer函数 function counterReducer(state { count: 0 }, action) {switch (action.type) {case INCREMENT:return { count: state.count 1 };case DECREMENT:return { count: state.count -…...

u2net网络模型训练自己数据集

单分类 下载项目源码 项目源码 准备数据集 将json转为mask json_to_dataset.py import cv2 import json import numpy as np import os import sys import globdef func(file):with open(file, moder, encoding"utf-8") as f:configs json.load(f)shapes configs…...

登录功能开发 P167重点

会话技术&#xff1a; cookie jwt令牌会话技术&#xff1a; jwt生成&#xff1a; Claims&#xff1a;jwt中的第二部分 过滤器&#xff1a; 拦截器&#xff1a; 前端无法识别controller方法&#xff0c;因此存在Dispa什么的...

数据架构图:从数据源到数据消费的全面展示

在这篇文章中&#xff0c;我们将探讨如何通过架构图来展示数据的整个生命周期&#xff0c;从数据源到数据消费。下面是一个使用Mermaid格式的示例数据架构图&#xff0c;展示了数据从源到消费的流动、处理和存储过程。 数据架构图示例 说明 数据源&#xff1a;分为内部数据源&…...

useEffect 与 useLayoutEffect 的区别

useEffect 与 useLayoutEffect 的区别 useEffect和useLayoutEffect是处理副作用的React钩子函数&#xff0c;有以下区别1. 执行时机不同2. 对性能影响不同3. 对渲染的影响不同&#xff1a;4. 使用场景不同 使用建议 useEffect和useLayoutEffect是处理副作用的React钩子函数&…...

OPENCV判断图像中目标物位置及多目标物聚类

文章目录 在最近的项目中&#xff0c;又碰到一个有意思的问题需要通过图像算法来解决。就是显微拍摄的到的医疗图像中&#xff0c;有时候目标物比较偏&#xff0c;也就是在图像的比较偏的位置&#xff0c;需要通过移动样本&#xff0c;将目标物置于视野正中央&#xff0c;然后再…...

分布式理论:拜占庭将军问题

分布式理论&#xff1a;拜占庭将军问题 介绍拜占庭将军的故事将军的难题 解决方案口信消息型拜占庭问题之解流程总结 签名消息型拜占庭问题之解 总结 介绍 拜占庭将军问题是对分布式共识问题的一种情景化描述&#xff0c;由兰伯特于1082首次发表《The Byzantine Generals Prob…...

从零开始Ubuntu24.04上Docker构建自动化部署(三)Docker安装Nginx

安装nginx sudo docker pull nginx 启动nginx 宿主机创建目录 sudo mkdir -p /home/nginx/{conf,conf.d,html,logs} 先启动nginx sudo docker run -d --name mynginx -p 80:80 nginx 宿主机上拷贝docker上nginx服务上文件到本地目录 sudo docker cp mynginx:/etc/nginx/ngin…...

阿里云 SAE Web:百毫秒高弹性的实时事件中心的架构和挑战

作者&#xff1a;胡志广(独鳌) 背景 Serverless 应用引擎 SAE 事件中心主要面向早期的 SAE 控制台只有针对于应用维度的事件&#xff0c;这个事件是 K8s 原生的事件&#xff0c;其实绝大多数的用户并不会关心&#xff0c;同时也可能看不懂。而事件中心&#xff0c;是希望能够…...

人口普查管理系统基于VUE+SpringBoot+Spring+SpringMVC+MyBatis开发设计与实现

目录 1. 系统概述 2. 系统架构设计 3. 技术实现细节 3.1 前端实现 3.2 后端实现 3.3 数据库设计 4. 安全性设计 5. 效果展示 ​编辑​编辑 6. 测试与部署 7. 示例代码 8. 结论与展望 一个基于 Vue Spring Boot Spring Spring MVC MyBatis 的人口普查管理…...

使用VBA快速将文本转换为Word表格

Word提供了一个强大的文本转表格的功能&#xff0c;结合VBA可以实现文本快速转换表格。 示例文档如下所示。 现在需要将上述文档内容转换为如下格式的表格&#xff0c;表格内容的起始标志为。 示例代码如下。 Sub SearchTab()Application.DefaultTableSeparator "*&quo…...

力扣题解1870

这道题是一个典型的算法题&#xff0c;涉及计算在限制的时间内列车速度的最小值。这是一个优化问题&#xff0c;通常需要使用二分查找来求解。 题目描述&#xff08;中等&#xff09; 准时到达的列车最小时速 给你一个浮点数 hour &#xff0c;表示你到达办公室可用的总通勤时…...

D3.js数据可视化基础——基于Notepad++、IDEA前端开发

实验:D3.js数据可视化基础 1、实验名称 D3数据可视化基础 2、实验目的 熟悉D3数据可视化的使用方法。 3、实验原理 D3 的全称是(Data-Driven Documents),是一个被数据驱动的文档,其实就是一个 JavaScript 的函数库,使用它主要是用来做数据可视化的。本次实…...

在Robot Framework中Run Keyword If的用法

基本用法使用 ELSE使用 ELSE IF使用内置变量使用Python表达式本文永久更新地址: 在Robot Framework中&#xff0c;Run Keyword If 是一个条件执行的关键字&#xff0c;它允许根据某个条件来决定是否执行某个关键字。下面是 Run Keyword If 的基本用法&#xff1a; Run Keyword…...

虚拟机ip突然看不了了

打印大致如下&#xff1a; 解决办法 如果您发现虚拟机的IP地址与主机不在同一网段&#xff0c;可以采取的措施之一是调整网络设置。将虚拟机的网络模式更改为桥接模式&#xff0c;这样它就会获得与主机相同的IP地址&#xff0c;从而处于同一网段。或者&#xff0c;您可以使用…...

LeetCode[中等] 763. 划分字母区间

给你一个字符串 s 。我们要把这个字符串划分为尽可能多的片段&#xff0c;同一字母最多出现在一个片段中。 注意&#xff0c;划分结果需要满足&#xff1a;将所有划分结果按顺序连接&#xff0c;得到的字符串仍然是 s 。 返回一个表示每个字符串片段的长度的列表。 思路 贪心…...

Java LeetCode每日一题

997. 找到小镇的法官 package JavaExercise20241002;public class JavaExercise {public static void main(String[] args) {int[][] array {{1,3},{2,3},{3,1}};Solution solution new Solution();System.out.println(solution.findJudge(3, array));} }class Solution {pu…...

数据结构--集合框架

目录 1. 什么是集合框架 2. 背后所涉及的数据结构以及算法 2.1 什么是数据结构 2.2 容器背后对应的数据结构 1. 什么是集合框架 Java 集合框架 Java Collection Framework &#xff0c;又被称为容器 container &#xff0c;是定义在 java.util 包下的一组接口 int…...

Win10鼠标总是频繁自动失去焦点-非常有效-重启之后立竿见影

针对Win10鼠标频繁自动失去焦点的问题&#xff0c;可以尝试以下解决方案&#xff1a; 一、修改注册表&#xff08;最有效的方法-重启之后立竿见影&#xff09; 打开注册表编辑器&#xff1a; 按下WindowsR组合键&#xff0c;打开运行窗口。在运行窗口中输入“regedit”&#x…...

智能涌现|迎接智能时代,算力产业重构未来

前言 OpenAI首席执行官山姆奥特曼在《智能时代》中描绘了一个令人振奋的未来图景&#xff0c;其中算力产业将扮演至关重要的角色。奥特曼预测&#xff0c;我们可能在“几千天内”迎来超级智能&#xff0c;这一进程将极大加速社会结构的智能化转型。 这一预测与算力产业的未来…...

C++实现分布式网络通信框架RPC(3)--rpc调用端

目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中&#xff0c;我们已经大致实现了rpc服务端的各项功能代…...

高危文件识别的常用算法:原理、应用与企业场景

高危文件识别的常用算法&#xff1a;原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件&#xff0c;如包含恶意代码、敏感数据或欺诈内容的文档&#xff0c;在企业协同办公环境中&#xff08;如Teams、Google Workspace&#xff09;尤为重要。结合大模型技术&…...

VTK如何让部分单位不可见

最近遇到一个需求&#xff0c;需要让一个vtkDataSet中的部分单元不可见&#xff0c;查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行&#xff0c;是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示&#xff0c;主要是最后一个参数&#xff0c;透明度…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心

当仓库学会“思考”&#xff0c;物流的终极形态正在诞生 想象这样的场景&#xff1a; 凌晨3点&#xff0c;某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径&#xff1b;AI视觉系统在0.1秒内扫描包裹信息&#xff1b;数字孪生平台正模拟次日峰值流量压力…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)

目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关&#xff0…...

群晖NAS如何在虚拟机创建飞牛NAS

套件中心下载安装Virtual Machine Manager 创建虚拟机 配置虚拟机 飞牛官网下载 https://iso.liveupdate.fnnas.com/x86_64/trim/fnos-0.9.2-863.iso 群晖NAS如何在虚拟机创建飞牛NAS - 个人信息分享...

Python 训练营打卡 Day 47

注意力热力图可视化 在day 46代码的基础上&#xff0c;对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...

深度剖析 DeepSeek 开源模型部署与应用:策略、权衡与未来走向

在人工智能技术呈指数级发展的当下&#xff0c;大模型已然成为推动各行业变革的核心驱动力。DeepSeek 开源模型以其卓越的性能和灵活的开源特性&#xff0c;吸引了众多企业与开发者的目光。如何高效且合理地部署与运用 DeepSeek 模型&#xff0c;成为释放其巨大潜力的关键所在&…...

第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10+pip3.10)

第一篇&#xff1a;Liunx环境下搭建PaddlePaddle 3.0基础环境&#xff08;Liunx Centos8.5安装Python3.10pip3.10&#xff09; 一&#xff1a;前言二&#xff1a;安装编译依赖二&#xff1a;安装Python3.10三&#xff1a;安装PIP3.10四&#xff1a;安装Paddlepaddle基础框架4.1…...

react菜单,动态绑定点击事件,菜单分离出去单独的js文件,Ant框架

1、菜单文件treeTop.js // 顶部菜单 import { AppstoreOutlined, SettingOutlined } from ant-design/icons; // 定义菜单项数据 const treeTop [{label: Docker管理,key: 1,icon: <AppstoreOutlined />,url:"/docker/index"},{label: 权限管理,key: 2,icon:…...