路由
-
路由:根据路由地址匹配组件的路由
-
安装:
npm install react-router-dom@6
路由初体验
// 入口文件index.js
...
// 1.引入路由,选择路由模式
import { BrowserRouter } from 'react-router-dom'
...
root.render(
<!-- 2.使用该路由模式 -->
<BrowserRouter>
<App />
</BrowserRouter>
)
// 路由表
// 引入路由
import { Routes, Route,Link } from 'react-router-dom'
// Routes:路由表(路由对象) Route:路由信息 Link:相当于a标签
// 引入组件
import Index from './views/Index/index'
import Login from './views/Login/index'
function App() {
return (
<div>
<div>
<Link to='/'>首页</Link> | <Link to='/login'>登录</Link>
</div>
<!-- 路由表 -->
<Routes>
<Route path='/' element={<Index></Index>}></Route>
<Route path='/login' element={<Login></Login>}></Route>
</Routes>
</div>
)
}
export default App
路由模式
-
两种路由模式
- hash:
HashRouter - history:
BrowserRouter
#***** 两种路由模式的区别: 答: `hash`:虽然出现在URL中,但不会被包括在HTTP,每次页面切换其实切换的是'#'之后的内容,而'#'后内容的改变并不会触发地址的改变,所以不存在发出请求,对后端完全没有影响,因此改变hash不会重新加载页面 `history`:利用了浏览器的历史记录栈,可以通过前进 后退控制页面的跳转,刷新是真实的改变url - hash:
-
引入
import { BrowserRouter, HashRouter } from "react-router-dom";BrowserRouter,HashRouter都是组件 -
使用
<!-- history模式 --> <BrowserRouter> <App /> </BrowserRouter> <!-- hash模式 --> <BrowserRouter> <App /> </BrowserRouter>
全局组件
-
路由( **
react-router-dom**)提供的全局组件 -
引入:
import {Routes,Route,Link,Outlet} from 'react-router-dom' -
Routes:创建路由表(路由对象) -
Route:创建路由信息path:跳转的目标路由地址element:显示的组件
-
Link:路由a标签to:跳转的目标路由地址
-
Outlet:路由视图占位符
路由跳转(useNavigate)
-
push:浏览器历史栈有记录的跳转,可回退 -
replace:历史栈没有记录,不可回退 -
go:前进和后退 -
语法:
-
引入:
import {useNavigate} from 'react-router-dom' -
使用:
let navigate = useNavigate()-
注意:路由hooks必须写到组件中
-
useNavigate()`useNavigate()`的返回值是一个方法,方法有2个参数 参数1:路由url 参数2:配置项(用来改变跳转方式和传递参数),是个对象 { replace:true, //replace跳转 state:{} // params传参 }// push语法(默认为push) navigate('/login') // replace语法 navigate('/login',{replace:true}) // go语法 navigate(2) //前进2个页面 navigate(-2) //后退2个页面
-
-
路由传参
-
路由地址可见(query参数)
- 字符串模板拼接
function Index(){ let navigate = useNavigate() let age=12 const btn()={ navigate('/home?name=小灰灰&&age=${age}') } return( <button onClick={()=>btn()}>query传参</button> ) } -
路由地址不可见(params传参)
- 使用
useNavigate()返回的方法的配置项(参数2)的state属性
function Index(){ let navigate = useNavigate() let age=12 const btn()={ navigate('/home',{ state:{age:14} }) } return( <button onClick={()=>btn()}>params传参</button> ) } - 使用
获取路由参数uselocation
-
获取(query)参数
-
使用第三方库
query-string解析query参数1.安装 `npm install query-string` 2.在需要解析的地方引入 `import qs from 'query-string';` 3.使用qs.parse解析 `qs.parse(需要解析的query参数)` -
使用
react-router-dom提供的useLocation来获取路由信息1.引入 `import {useLocation} from 'react-router-dom'` 2.使用 `let location = useLocation()` -
使用
location.search获取query参数
import { useNavigate, useLocation } from "react-router-dom"; // 引入路由提供的hooks import qs from "query-string"; // 引入解析参数的第三方库 function Me() { let navigate = useNavigate() // 路由跳转 let location = useLocation() // 路由信息 console.log(location); // 路由信息 console.log(location.search); // 参数 console.log(qs.parse(location.search)); //解析后的参数 return ( <div> <h1>我的</h1> <button onClick={() => navigate('/home')}>去首页</button> </div> ) } -
-
获取(params)参数
- 使用
location.state获取params参数
import { useNavigate, useLocation } from "react-router-dom"; // 引入路由提供的hooks function Me() { let navigate = useNavigate() // 路由跳转 let location = useLocation() // 路由信息 console.log(location); // 路由信息 console.log(location.state); // 参数 console.log(location.state); //解析后的参数 return ( <div> <h1>我的</h1> <button onClick={() => navigate('/home')}>去首页</button> </div> ) } - 使用
路由模块化
- 在路径
src/router/index.js中创建路由表,路由表也是一个组件 - 再到根组件中进行引入,使用路由表这个组件
import Index from '../views/Index/index'
import Me from '../views/Me/index'
function RouterList(){
return (
<Routes>
<Route path="/" element={<Index></Index>}></Route>
<Route path="/me" element={<Me></Me>}></Route>
</Routes>
)
}
export default RouterList
嵌套路由
-
配置嵌套路由
- 在路由组件中进行嵌套,直接添加路由信息
- 嵌套路由的路由url会自动与父级路由url进行拼接
- 在父级路由组件中使用路由占位符
<Outlet>展示嵌套路由组件
<Routes> <Route path="/" element={<Index></Index>}> <!-- 嵌套路由 --> <Route path="/indexshow" element={<IndexShow></IndexShow>}></Route> </Route> <Route path="/home" element={<Home></Home>}></Route> </Routes> -
展示嵌套路由
return( <div> <h1>index</h1> <!-- 展示嵌套路由 --> <Outlet></Outlet> </div> )
路由重定向
- 使用自定义hooks
// 引入路由跳转和路由信息
import { useEffect } from "react";
import { useNavigate, useLocation } from "react-router-dom";
function useRedirect() {
let location = useLocation() //路由信息
let navigate = useNavigate() //路由跳转
console.log('路由当前', location.pathname);
// 监听当前路由
useEffect(() => {
if (location.pathname == '/') {
navigate('/home') //重定向
}
}, [location.pathname])
}
export default useRedirect
路由守卫
- 作用:时刻监听着路由地址的改变
// 例:校验是否登录
import { useNavigate, useLocation } from "react-router-dom"; // 引入路由跳转和路由信息
import { useEffect } from "react"; // react的hooks
function useBeforEach(params) {
let navigate = useNavigate() //路由跳转
let location = useLocation() //路由信息
// 监听路由
useEffect(() => {
if (location.pathname != '/login') {
if (!sessionStorage.getItem('token')) {
navigate('/login')
}
}
}, [location.pathname])
}
export default useBeforEach
- 由于路由守卫和路由重定向都需要监听路由信息,所以可以进行合并
import { useLocation, useNavigate } from "react-router-dom"; // 导入路由信息和路由跳转
import { useEffect } from "react"; //react的hooks
function useRedBef() {
let location = useLocation() //路由信息
let navigate = useNavigate() //路由跳转
// 监听路由
useEffect(() => {
// 1.判断是否内部页面
if (location.pathname != '/login') {
// 2.路由守卫
if (sessionStorage.getItem('token')) {
// 3.重定向
if (location.pathname == '/') {
navigate('/home')
}
} else {
navigate('/login')
}
}
}, [location.pathname])
}
export default useRedBef
404页面
<Route path='*' element={<NotFind ></NotFind >}></Route>
首页白屏
-
配合 路由懒加载 使用
-
语法
<Suspense fallback={先展示的组件}> <!-- 路由表 --> </Suspense>
路由懒加载
-
项目启动时不会加载所有页面,而是按需加载,提高了项目首次加载的速度
-
语法:
React.lazy(()=>import('组件路径')) // 返回路由懒加载数据 -
结合首页白屏
- 语法:
<Suspense fallback={先展示的组件}> <!-- 路由表 --> </Suspense>
- 语法:
import { Routes, Route, Link } from "react-router-dom"; // 引入路由全局组件
import React, { Suspense } from "react"; // react方法和首页白屏
// 懒加载组件
let Index = React.lazy(() => import('../views/Index/index'))
let Login = React.lazy(() => import('../views/Login/index'))
let Me = React.lazy(() => import('../views/Me/index'))
function RouterList() {
return (
<div>
<!-- 首页白屏 -->
<Suspense fallback={<div className="aa">loading...</div>}>
<Routes>
<Route path='/home' element={<Index />}></Route>
<Route path='/login' element={<Login />}></Route>
<Route path='/me' element={<Me />}></Route>
<Route path='*' element={<h1>404</h1>}></Route>
</Routes>
</Suspense>
</div>
);
}
-
封装自动处理懒加载组件
import { Routes, Route, Link } from "react-router-dom"; // 引入路由全局组件 import React, { Suspense } from "react"; // react方法和首页白屏 // 自动处理懒加载组件 function AutoLazy(name){ let Com Com = React.lazy(()=>import(`../views/${name}/index`)) // 返回懒加载组件 return <Com></Com> } function RouterList() { return ( <div> <!-- 首页白屏 --> <Suspense fallback={<div className="aa">loading...</div>}> <Routes> <Route path='/home' element={AutoLazy('Index')}></Route> <Route path='/login' element={AutoLazy('Login')}></Route> <Route path='/me' element={AutoLazy('Me')}></Route> <Route path='*' element={<h1>404</h1>}></Route> </Routes> </Suspense> </div> ); }
动态路由
- 动态路由:根据后端数据动态生成
function ListItem(list){
if(list.length>0){
return list.map((item,index)=>{
return <Route key={index} path="bashbord" element={LazyC('DashBord')}></Route>
})
}
}
- 路由组件执行流程:到内部页面,需要再执行路由表>redux(项目中讲)
- 总结:
- 根据后端数据动态生成
- 登录获取权限
- 到内部页面,重新执行路由表(只能执行一次)
- (
由于路由守卫和重定向使用了路由跳转,所以会重新创建组件,所以不应放在根组件,应放到布局组件中)
- (
- 权限:
- 基础版本:前端:内部和外部页面=>导航守卫 后端:内部和外部接口 (官网)
- 进阶版本:页面:侧边栏导航、动态路由 (后台管理系统)
- 终极版本:可以自己设置权限 (后台管理系统)