react-dom-router6 动态渲染路由+路由拦截

✅ 作者 : 布克吉

🍎简介 : 专注于前端开发,微信小程序,后台管理(Vue+React)

               本博客主要用于分享前端技术知识,更多内容请看下方👇

✨人生态度 :☀️Eventually everything will be fine!☀️

前言

动态渲染,顾名思义就是在数据发生改变时根据已有的逻辑自动调整,以不变应万变。

第一可以让代码面对复杂的业务需求时,更加灵活和易于维护,第二看起来也更加美观。

目录

一、动态渲染路由

1.新建routes.js文件

2.在最外层index.js中引入

3.在需要的使用的页面home.js中动态渲染

二、路由拦截

1.新建一个withGuard.js文件。

2.主页面home.js使用该拦截组件

补充:


一、动态渲染路由

router6中我们使用useRoutesOutlet来实现动态渲染路由,以下为实现方法:

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)

网上也有其他文章介绍了相关知识。还封装成了组件,研究了许久发现不会用,大家可以参考下。

react-router v6 路由统一管理及路由拦截方案_react.js_醉逍遥neo-华为云开发者联盟上一篇分享了react-router v5 版本的路由管理及拦截方案,但也存在一些缺陷,例如不支持嵌套路由、不支持动态路由参数等。后来看到了react-router v6 版本useRoutes api 的特性,决定升级到v6版本,并对路由管理和路由拦截的实现方案进行了重构。v6版本目前网上的文章寥寥无几,实现过程基本靠自己摸索,下面分享具体方案。一、react-router v6官方文档:htt 醉逍遥neo 华为云开发者联盟icon-default.png?t=N7T8https://huaweicloud.csdn.net/638f1232dacf622b8df8e82c.html

以上就是本文所有内容了,如果觉得可以,欢迎点赞、收藏+关注!

  • 21
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
React Router 提供了一些钩子函数来拦截路由,这样我们就可以在路由跳转之前或之后进行相关的操作。下面是一个简单的路由拦截示例: ```javascript import React from 'react'; import { BrowserRouter as Router, Route, Link, Redirect } from 'react-router-dom'; const isAuthenticated = true; const PrivateRoute = ({ component: Component, ...rest }) => ( <Route {...rest} render={(props) => ( isAuthenticated === true ? <Component {...props} /> : <Redirect to='/login' /> )} /> ); const LoginPage = () => ( <div> <h1>Login Page</h1> </div> ); const HomePage = () => ( <div> <h1>Home Page</h1> </div> ); const App = () => ( <Router> <div> <ul> <li><Link to='/'>Home</Link></li> <li><Link to='/login'>Login</Link></li> </ul> <hr /> <PrivateRoute exact path='/' component={HomePage} /> <Route path='/login' component={LoginPage} /> </div> </Router> ); export default App; ``` 在上面的代码中,我们定义了一个 `PrivateRoute` 组件来实现路由拦截。如果用户已经认证,则展示 `component` 组件,否则重定向到登录页面。 另外,我们还定义了两个页面组件:`HomePage` 和 `LoginPage`。在 `App` 组件中,我们使用 `PrivateRoute` 组件来保护 `HomePage` 组件,这样只有已经认证的用户才能访问该页面。 如果你想在路由跳转之前进行相关的操作,可以使用 `react-router` 提供的 `Prompt` 组件。下面是一个简单的示例: ```javascript import React, { useState } from 'react'; import { BrowserRouter as Router, Route, Link, Prompt } from 'react-router-dom'; const App = () => { const [isBlocking, setIsBlocking] = useState(false); const handleChange = (event) => { setIsBlocking(event.target.value.length > 0); }; return ( <Router> <div> <ul> <li><Link to='/'>Home</Link></li> <li><Link to='/about'>About</Link></li> </ul> <hr /> <Prompt when={isBlocking} message={location => `Are you sure you want to go to ${location.pathname}?`} /> <Route exact path='/' render={() => ( <div> <h1>Home Page</h1> <input type='text' onChange={handleChange} /> </div> )} /> <Route path='/about' render={() => ( <div> <h1>About Page</h1> </div> )} /> </div> </Router> ); }; export default App; ``` 在上面的代码中,我们使用 `Prompt` 组件来拦截路由,在用户输入内容时,如果尚未保存,就弹出提示框。提示框的内容可以通过 `message` 属性来设置。如果用户选择离开当前页面,则路由会跳转到目标页面。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值