✅ 作者 : 布克吉
🍎简介 : 专注于前端开发,微信小程序,后台管理(Vue+React)
本博客主要用于分享前端技术知识,更多内容请看下方👇
✨人生态度 :☀️Eventually everything will be fine!☀️
前言
动态渲染,顾名思义就是在数据发生改变时根据已有的逻辑自动调整,以不变应万变。
第一可以让代码面对复杂的业务需求时,更加灵活和易于维护,第二看起来也更加美观。
目录
一、动态渲染路由
router6中我们使用useRoutes和Outlet来实现动态渲染路由,以下为实现方法:
1.新建routes.js文件
import { useRoutes} from 'react-router-dom';
// 1. 准备一个路由数组 数组中定义所有的路由对应关系
const routes = [{
path: '/',
element: <Home/>,
children:[
{
path: '/page//*',
meta:{
title:'页面一',
role:[1,2,3]
},
element: <Page1/>,
children:[
{
path: 'page1child1',
meta:{
title:'页面一子页面1',
role:[1,2]
},
element: <Page1Child2/>
},
{
path: 'page1child2',
meta:{
title:'页面一子页面2',
role:[1,3]
},
element: <Page1Child2/>
}]
]
}]
//以函数形式,并在内部导出
function AppRoutes() {
return useRoutes(routes)
}
function RouterModel() {
return (
<div>
<AppRoutes/>
</div>
)
}
export {routes,RouterModel}
2.在最外层index.js中引入
import ReactDOM from 'react-dom';
import {BrowserRouter} from "react-router-dom"
import {RouterModel} from '../Router/route.js'
ReactDOM.render(
<BrowserRouter>
<RouteModel />
</BrowserRouter>
, document.getElementById('root'));
3.在需要的使用的页面home.js中动态渲染
import {routes} from '../Router/route.js'
import React, { Component } from 'react';
import { Navigate,Outlet} from 'react-router-dom';
import {Layout, Menu} from 'antd';
const {Content} = Layout;
//用于保存动态路由的数组
let menuDom = []
class Home extends Component {
constructor (props) {
super(props);
this.state = {
}
}
componentDidMount() {
menuDom = this.getMenuDom()
}
//根据用户角色动态生成路由菜单(根据实际情况做调整)
getMenuDom = ()=>{
let menuList = []
let menuDomData = []
//获取当前用户角色
let role = atob(LocalStorage.getItems('currentRole'))*1
routes.forEach(item=>{
if(item.children){
item.children.forEach(v=>{
if(v.meta){
if(v.meta.role.find(r=>role===r)!==undefined){
if(v.children){
let newChildren = []
for (var i = 0; i < v.children.length; i++) {
v.children[i].meta.role.forEach(r=>{
if(role===r){
newChildren.push(v.children[i])
}
})
}
v.children = newChildren
}
menuList.push(v)
}
}
})
}
})
//存入本地缓存数据
LocalStorage.SetObjItems('menuData',menuList)
menuList.forEach((item,index)=>{
menuDomData.push((
<Menu.Item key={index}>
<Link to={item.path}>{item.meta.title}</Link>
</Menu.Item>
))
})
return menuDomData
}
render(){
return(
<Menu theme="dark">
{menuDom}
</Menu>
{/* 渲染对应的页面*/}
<Content style={{ padding: '4px 15px',backgroundColor:'#fff' }}>
<Outlet />
</Content>
)
}
}
其中Oulet会自动渲染路由对用的页面,这里是useRoutes起到的作用
二、路由拦截
在上述动态渲染路由时,提到了用户角色,我们会根据用户角色的权限,来动态判断,具体页面中的子路由。
但是有一个问题,我们只是根据用户的角色来动态生成菜单数组进行渲染,如果直接在地址栏输入页面的地址,仍然会进行跳转,为此,提供了一个方法来拦截非法路由并跳转到404页面。
这里用到了reouter6中的useLocation,来获取当前页面的路由
1.新建一个withGuard.js文件。
import { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { Navigate, useLocation } from "react-router-dom";
import LocalStorage from '../Common/Common.js'
function Guard({ Cmp, ...props }) {
console.log('Cmp', Cmp, props);
const { pathname } = useLocation();
/* const { user } = useSelector(state => state);
const dispatch = useDispatch();
useEffect(() => {
// 若没有用户信息,保存现在的地址
if (!user) {
dispatch({
type: 'prevPath',
prevPath: pathname
})
}
}, [user]) */
// 若有用户信息正常展示组件,若没有跳转到登录页
console.log(pathname);
LocalStorage.SetItems('pathname',pathname)
//根据需求处理获取到的当前的路由信息
let pathnameArr = pathname.split('/').filter(path=>path!==''&&path!=='*')
console.log(pathnameArr);
let path = pathnameArr[pathnameArr.length-1]
console.log(path);
//函数用于验证当前路由是否合法,否则返回false,并跳转到404页面
function validPath(){
let flag = false
let menuData = []
//此处获取home页面存入本地的缓存数据(菜单数组)
menuData = LocalStorage.getObjItems('menuData')
console.log(menuData);
let regex = new RegExp(path);
for (var i = 0; i < menuData.length; i++) {
if(regex.test(menuData[i].path)){
flag = true
break;
}else if(menuData[i].children){
menuData[i].children.some(v=>{
if(regex.test(v.path)){
flag = true
return true
}
})
}
}
console.log(flag);
return flag
}
let _token= LocalStorage.getItems('_t')
// 获取路由与menu 的path 匹配
return _token? (validPath()? <Cmp {...props} />:<Navigate to="/404" />):<Navigate to="/login" />
}
// 一个高阶函数,将组件和props都传递给函数组件Guard
export default function withGuard(Cmp) {
return (props) => <Guard Cmp={Cmp} {...props} />
}
2.主页面home.js使用该拦截组件
import WithGuard from '../Router/WithGuard.js'
/*
此处省略500行
*/
//页面导出时
export default WithGuard(Home);
由此可实现动态路由渲染和拦截🚀🚀🚀
补充:
1.代码中使用的LocalStorage为简单的自行封装使用
2.关于404页面,这里简单渲染一下,页面中倒计时五秒后便返回原来页面
import React, { Component } from 'react';
import withRouter from "../Router/widthRouter";
import {Empty } from 'antd';
import LocalStorage from '../Common/Common.js'
let timer = null
class Page404 extends Component {
constructor(props){
super(props);
this.state = {
time:5
}
}
componentDidMount(){
let lastPath = LocalStorage.getItems('pathname')
let num
if(lastPath){
timer = setInterval(()=>{
num = this.state.time
num = num - 1
this.setState({
time:num
},()=>{
if(this.state.time===0){
this.props.navigate(lastPath)
}
})
},1000)
}
}
componentWillUnmount(){
clearInterval(timer)
}
render(){
return(
<Empty
imageStyle={{ marginTop: 300 }}
description={
<span>
该页面不存在或无权限访问, <span style={{fontSize:'18px',color:'#f00'}}>{this.state.time}</span> 秒后,返回上一个页面
</span>
}
>
</Empty>
)
}
}
export default withRouter(Page404)
网上也有其他文章介绍了相关知识。还封装成了组件,研究了许久发现不会用,大家可以参考下。
以上就是本文所有内容了,如果觉得可以,欢迎点赞、收藏+关注!