----------------------------续----------------------------------------
前面写了一篇文章,关于全局拦截守卫。虽然实现了全局拦截。但是并不完美。我们只能针对一级路由有效。也就是整个routes数组只有一层。如果还有嵌套路由,二级,三级,就无能为力。因为我们在页面切换的时候,我们想获取到当前路由path和数组中匹配的那条数据,是通过 const targetRouteObj = routeData.find((item) => item.path == pathname)这个方法实现的。而这个方法只做到了一层。
想一想还有没有更好的办法实现路由守卫呢?今天尝试用另外一种方法来实现,并且它支持嵌套路由:
-------------------------------------app.js-----------------------------------------------
import React from 'react'
import { BrowserRouter as Router, Switch, Route } from "react-router-dom"
import routes from "./router/routes"
import AuthRoute from "./router/authRoute"
import { MainRoute } from "./router/routeConfig"
function App() {
return (
<MainRoute></MainRoute>
);
}
export default App;
--------------------------------routes.js-----------------------------------------------------
import React from 'react'
import Layout from "../pages/Layout"
import Login from "../pages/Login"
import About from "../pages/About"
import NotFound from "../pages/NotFound"
import UserInfo from "../pages/UserInfo"
import Info from "../pages/Info"
import News from "../pages/News"
import Product from "../pages/Product"
const routes = [
{ name: "", path: "/", component:Login, children:[],exact:true},
{ name: "login", path: "/login", component:Login,children:[],exact:false},
{
name: "layout",
path: "/layout",
auth: true,
component: Layout,
exact:false,
children: [
{
path: "/layout/news",
name: "news",
auth: true,
component: News
},
{
path: "/layout/product",
name: "product",
auth: true,
component: Product
},
{
path: "/layout/userInfo",
name: "userInfo",
auth:true,
component: UserInfo
},
{
path: "/",
name: "news",
auth: true,
component: News
},
],
},
{ name: "about", path: "/about", component: About,children:[],auth:true, exact: false },
{ name: "info", path: "/info", component: Info,children:[],auth:false, exact: false },
{ name: "404", path: "/404", component: NotFound,children:[], exact: false },
]
export default routes;
--------------------------------routeConfig.js-----------------------------------------------------
import React from 'react'
import routes from "./routes"
import { BrowserRouter as Router, Route, Switch, Redirect } from "react-router-dom"
import Layout from "../pages/Layout"
//一级路由
const MainRoute = () => {
return (
<Router>
<Switch>
{
routes.map((item, index) => {
if (item.auth) {
console.log("1111")
return (
<PrivateRoute
key={index}
path={item.path}
{...item}
component={item.component }
>
</PrivateRoute>
)
} else {
return (<NormalRoute key={index} {...item}></NormalRoute>)
}
})
}
<Redirect to="/404"></Redirect>
</Switch>
</Router>
)
}
//二级路由
function SubRoute() {
const subRoutes = routes&&routes.filter(item => item.children.length > 0)[0]['children']
return (
<Switch>
{subRoutes.map((item,index) => {
if (item.auth) {
return (
<PrivateRoute
key={index}
path={item.path}
{...item}
component={ item.component}
>
</PrivateRoute>
)
} else {
return (<NormalRoute key={index} {...item}></NormalRoute>)
}
})}
<Redirect to="/404"></Redirect>
</Switch>
)
}
//私有路由,需要拦截
const PrivateRoute = (props) => {
let isLogin = localStorage.getItem("isLogin")
let { location } = props;
return (
<Route render={
() => {
if (isLogin) {
return (<Route path={props.path} component={props.component }></Route>)
} else {
return <Redirect to="/" ></Redirect>
}
}
}>
</Route>
)
}
//开放路由,无须拦截
const NormalRoute = (route) => {
let { location } = route;
return (
<Route
exact={route.exact}
path={route.path}
component={ route.component}
>
</Route>
)
}
export { MainRoute,SubRoute}
-------------------------------------------layout.js----------------------------------------------
import React from 'react'
import { useHistory} from "react-router-dom"
import homeStyle from "./home.module.less"
import MainNav from "../MainNemu"
import { SubRoute } from "../../router/routeConfig"
function Layout() {
let history=useHistory()
const loginOut = () => {
localStorage.clear()
history.replace("/login")
}
return (
<div className={homeStyle['layout-container']}>
<header className={homeStyle['layout-top']}>
<img src="https://ali-image-test.dabanjia.com/image/20190320/DBJ_1553077801738_3899.png?x-oss-process=image/resize,m_lfit,h_80,w_300" alt=""/>
</header>
<main className={homeStyle['layout-main']}>
<section className={homeStyle['layout-side']}>
<MainNav></MainNav>
</section>
<section className={homeStyle['layout-content']}>
<SubRoute></SubRoute>
</section>
</main>
</div>
)
}
export default Layout
---------------------------------------login.js---------------------------------------------------
import React, { useState } from 'react'
import { useHistory } from "react-router-dom"
import { Button } from 'antd';
import "./login.css"
function Login() {
const [user,setUser]=useState("")
const [password, setPassword] = useState("")
let history=useHistory()
console.log("登录history:", history)
const getVal = (obj) => {
let type = obj.target.dataset.type
if (type == "user") {
setUser(obj.target.value)
} else {
setPassword(obj.target.value)
}
}
const login = () => {
localStorage.setItem("isLogin", true)
history.push("/layout")
}
return (
<div className="form-box">
<p>
<input type="text" name="" value={user } data-type="user" onChange={getVal} placeholder="请输入用户名"/>
</p>
<p>
<input type="password" name="" value={ password} data-type="password" onChange={getVal} placeholder="请输入密码"/>
</p>
<p>用户名是:{ user }</p>
<p>密码是:{ password}</p>
<p>
<Button type="primary" onClick={ login }>Primary Button</Button>
</p>
</div>
)
}
export default Login
这个实例能实现全局守卫的作用。但是有一个缺陷点:就是在登录以后。如果手动输入url地址栏到login,还是会回到login页面。因为整体的逻辑是按照是否开放页面来区分的。login属于开放页面,所以即使登录了,还是可以回到登录、