项目实战动态路由鉴权

reduxjs/toolkit+ 动态路由实现

第一步骤

封装redux/toolkit

 
 
1.安装
cnpm i --save-dev @reduxjs/toolkit redux
 
 
2.创建store文件
//创建唯一store对象
import { configureStore } from "@reduxjs/toolkit";

const store = configureStore({
//多个reducer合并 module模块化
reducer: {},
devTools: true,
});

export default store;
 
 
3.创建user slice切片
//用户模块下的slice
import { createSlice } from "@reduxjs/toolkit";

//创建切片
const userSlice = createSlice({
name: "User", //切片名称
//当前切片状态值
initialState: {
token: null,
routes: [],
},
reducers: {
//事件类型
saveToken(state, action) {},
saveRoutes(state, action) {},
},
});

//导出映射的action
export const { saveRoutes, saveToken } = userSlice.actions;

//导出合并的reducer
export const userReducer = userSlice.reducer;

第二步骤

将store和react关联

安装react-redux关联

 
 
  1. cnpm i --save-dev react-redux
 
 
main.js
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import "./index.css";

//引入store
import store from "./store/index";
//引入react-redux
import { Provider } from "react-redux";
ReactDOM.createRoot(document.getElementById("root")).render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);

第三步骤

 
 
在系统主界面index 下 发送网络请求获取menu菜单 解析antd menu显示。 之后做状态管理存储

//存储用户菜单到状态机
dispatch(saveRoutes(res.data.data));

对应slice中代码
reducers: {
//事件类型
saveToken(state, action) {},
saveRoutes(state, action) {
//获取参数
let { payload } = action;
state.routes = payload;
},
},

第二种写法:在toolkit中执行异步编程直接存储(toolkit内置了异步编程 thunk)

toolkit内置API 创建异步编程

 
 
1.在slice切片中创建异步编程
//用户模块下的slice
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
//创建异步编程
const getMenuThunk = createAsyncThunk("menuThunk", async () => {
//异步网络
return 1;
});

2.createAsyncThunk 本身和slice切片没关系,需要关联监听异步编程。
dispatch 一组 type 为 pending/fulfilled/rejected 的 action。
 
 
异步编程slice
//用户模块下的slice
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
//创建异步编程
export const getMenuThunk = createAsyncThunk("menuThunk", async (args) => {
console.log(args);
//异步网络
return 1;
});
//创建切片
const userSlice = createSlice({
name: "User", //切片名称
//当前切片状态值
initialState: {
token: null,
routes: [],
},
reducers: {
//事件类型
saveToken(state, action) {},
saveRoutes(state, action) {
//获取参数
let { payload } = action;
state.routes = payload;
},
},
//extraReducers 监听异步编程
extraReducers: {
[getMenuThunk.pending](state, action) {
console.log("pending");
},
[getMenuThunk.fulfilled](state, action) {
console.log("fulfilled", action);
},
[getMenuThunk.rejected](state, action) {
console.log("rejected");
},
},
});

//异步触发
dispatch(getMenuThunk(123));

第四步骤

开始配置路由。

分析:路由菜单已经状态管理。更新路由需要让app.jsx组件更新(routes配置更新—->路由更新)

 
 
App.jsx
//引入路由相关
import { useEffect, useState } from "react";
import { useSelector } from "react-redux";
import { BrowserRouter } from "react-router-dom";
//路由插件
import RouterView from "react-router-waiter";
import { routes, onBeforeRoute } from "./router/index";

export default () => {
let [rots, setRots] = useState(routes);
//可以自动监听到路由数据变化
let rts = useSelector((state) => state.users.routes);
useEffect(() => {
console.log(rts);
//如果rts是[] 不需要设置
}, [rts]);
return (
<>
<BrowserRouter>
<RouterView routes={rots} onRouteBefore={onBeforeRoute}></RouterView>
</BrowserRouter>
</>
);
};

第五步骤

 
 
app.jsx
根据条件实现路由数据解析
useEffect(() => {
console.log(rts);
//如果rts是[] 不需要设置
rts.length && patterRouter(rts);
}, [rts]);

//路由文件中定义数据解析方法

//路由数据解析 可以直接解析为路由的配置 解析为组件懒加载
//[{path:'',component:'',meta:{}}]
/*
component: "pms/housepay"
hidden: false
meta: {title: '商铺综合收费', icon: 'money', noCache: false, link: null}
name: "Housepay"
path: "housepay"
*/
export const patterRouter = (config) => {
//存储解析之后的路由数据
let rts = [];
//内部定义基本递归
function patter(args) {
args.forEach((item) => {
!item.children
? rts.push({
path: item.path,
component: item.component,
meta: item.meta,
})
: patter(item.children);
});
}
patter(config);
console.log(rts);
};

扫描二维码关注公众号,回复: 14834050 查看本文章

第六步骤

解析子路由组件component实现懒加载

路由配置文件中懒加载解析

 
 
vite import.meta.glob("../views/**/*.jsx")
原生脚手架 ()=>import("")


//全局懒加载
const modules = import.meta.glob("../views/children/**/*.jsx");


//懒加载组件方法
function lazyLoad(path) {
let ps = modules[`../views/children/${path}.jsx`];
console.log(ps);
}


export const patterRouter = (config) => {
//存储解析之后的路由数据
let rts = [];
//内部定义基本递归
function patter(args) {
args.forEach((item) => {
!item.children
? rts.push({
path: item.path,
component: lazyLoad(item.component),//懒加载
meta: item.meta,
})
: patter(item.children);
});
}
patter(config);
console.log(rts);
};

在当前解析路由数据懒加载之后在进行数据合并

 
 
//二级动态路由数据和静态二级合并
routeList[0].children = routeList[0].children.concat(rts);

到App.jsx文件中进行routes更新

 
 
useEffect(() => {
console.log(rts);
//如果rts是[] 不需要设置
rts && rts.length && setRots(patterRouter(rts));
}, [rts]);
//setRots 该方法更新

测试整体动态路由。刷新造成路由回到默认首页。

第七步骤

刷新网页,当前路由正常显示。

 
 
当前路由是 /housePay 刷新之后 /housePay

//将二级子路由静态 改为懒加载 执行守卫
//守卫中写入当前路径缓存
//缓存pathname路径
localStorage.setItem("_path", pathname);

刷新的时候动态修改二级重定向为上次点击的路由

 
 
//读取上次的路由路径
let path = localStorage.getItem("_path");
//静态路由
let routeList = [
{
path: "/",
element: <Admin />,
children: [
{
path: "index",
component: () => import("../views/children/Index"),
},
{
path: "/",
redirect: path, //定向到上次访问路由
},
],
},

刷新路由回到菜单对应位置

官方API

 
 
属性默认展开:
defaultOpenKeys={["//fee", "payment"]}
defaultSelectedKeys={["housepay"]}

点击当前子集展开,其他子集收起

 
 
openKeys={openKeys}
onOpenChange={onOpenChange}
//该属性放置 menu菜单一级key
//控制效果是当前展开其余收起
const rootSubmenuKeys = [
"//fee",
"//workflow",
"//owner",
"/config",
"/system",
];

openKeys={openKeys}
onOpenChange={onOpenChange}
使用之后 默认初始化展开失效
const [openKeys, setOpenKeys] = useState(["//fee", "payment"]); //默认展开

分析得知,刷新的路由路由可以控制menu菜单默认选中

 
 
defaultSelectedKeys={["housepay"]}
//使用useLocation 获取路由路径
let location = useLocation();
//默认选中为当前路由路径
defaultSelectedKeys={[location.pathname.replace(/\//g, "")]}

menu菜单自动展开

 
 
只需要控制开开默认值
const [openKeys, setOpenKeys] = useState(["//fee", "payment"]);

//在官方提供的选中方法中存储当前用户选择
const onOpenChange = (keys) => {
//存储当前用户选择的菜单
localStorage.setItem("_hismenu", keys);

const latestOpenKey = keys.find((key) => openKeys.indexOf(key) === -1);
if (rootSubmenuKeys.indexOf(latestOpenKey) === -1) {
setOpenKeys(keys);
} else {
setOpenKeys(latestOpenKey ? [latestOpenKey] : []);
}
};
 
 
let his = localStorage.getItem("_hismenu");
const [openKeys, setOpenKeys] = useState(his ? his.split(",") : []);
//可以实现刷新默认展开

猜你喜欢

转载自blog.csdn.net/m0_74331185/article/details/129996748
今日推荐