react脚手架:
全局安装:npm i create-react-app -g
查看脚手架版本:create-react-app -V
脚手架创建项目:
create-react-app myrouter(要求node版本最低是v10.14.2)
react路由:
安装:npm i react-router-dom
基本使用:
1、路由的形式:
hash路由:HashRouter
history路由:BrowserRouter
路由的所有配置必须在HashRouter或BrowserRouter的包裹范围之内
2、路由的显示:
route:
作用:用来配置路由以及路由的显示
配置项:
path:路由匹配的路径
component:当路径匹配成功后需要渲染的组件(值为组件名称)
render:当路径匹配成功后需要渲染的组件(值是一个函数)
exact:完全匹配
3、路由跳转的方式:
①a标签
<a href="#/home">首页</a> <a href="#/classify">分类</a> <a href="#/order">订单</a>
②Link(没有选中标识的,使用场景:返回)
<Link to='/home'>首页</Link> <Link to='/order'>订单</Link> <Link to='/classify'>分类</Link>
如果重复点击某个路由会报警告:
警告:哈希历史不能推送相同的路径;新的条目不会被添加到历史堆栈中
③NavLink(使用场景:底部导航、有选中标识的导航)
<NavLink to='/home' activeClassName='aaa' activeStyle={{background:'yellow'}}>首页</NavLink> <NavLink to='/order'>订单</NavLink> <NavLink to='/classify'>分类</NavLink>
配置项:
to:需要跳转的路径
activeClassName:更改选中后的标识
activeStyle:选中后的样式
④编程式导航
4、路由传值:
①动态路由:(地址栏上有参数:details/xxx/xxx,刷新不丢失)
在定义的时候通过 /:属性 的方式来定义传递的属性
在路由跳转的时候通过 /值 的方式进行传值
在需要接收数据的页面通过 this.props.match.params 来接收
②query传值:(地址栏上有参数:details?id=xxx&name=xxx,刷新不丢失)
路由:
在路由跳转的时候通过 query 进行传值
在需要接收数据的页面通过 this.props.location.search 来接收(?id=0&name=%E9%A6%99%E8%95%89)
③内存传值:(地址栏上没有参数,刷新会丢失)
路由:
在路由跳转的时候通过 to={{pathname:'', query:{}}} 进行传值
在需要接收的页面通过 this.props.location.query 来接收
5、路由嵌套:
6、编程式导航:
this.props.history.push()
this.props.history.goBack()
this.props.history.goForward()
this.props.history.go()
this.props.history.replace()
7、component渲染和render渲染的区别:
①在route组件中通过component属性进行页面渲染的时候会默认的给当前组件传递三个值(history match location)
②render渲染的时候可以渲染组件也可以渲染标签
③render渲染的时候可以进行传值
④一般情况下会通过render的方式进行路由的嵌套
⑤render可以进行更多的业务逻辑
8、路由重定向:
import {Redirect} from 'react-router-dom'
9、Switch
作用:只匹配一个路由
10、路由懒加载:
①安装:npm i react-loadable
②引入并使用:
11、withRouter:
高阶组件:
作用:可以给当前组件的props传入一个对象,这个对象就是路由的三个值{history match location}
当使用render方式渲染组件时,如果没有手动去传路由的三个值:
此时在order组件中的this.props是一个空对象:
使用withRouter将组件包裹:
此时再打印this:
说明withRouter给当前被包裹的组件传递了路由的三个值,就可以正常使用编程式导航等功能了。
路由表封装:
1、在components中新建index.js文件,将所有的页面都用懒加载的方式引入,整体导出出去
2、src下新建router/index.js:将路由放入路由表中
import { Home, Classify, HotMovie, CommingMovie, ClassifyOrder, Order, Login } from '../components' // 有layout布局的路由表 export const layoutRoutes = [ { path: '/home', component: Home, icon: '', meta: {} }, { path: '/classify', component: Classify, icon: '', meta: {}, children: [ { path: '/classify/hotMovie', component: HotMovie, meta: {} }, { path: '/classify/commingMovie', component: CommingMovie, meta: {} }, { path: '/classify/order', component: ClassifyOrder, meta: {} } ] }, { path: '/order', component: Order, icon: '', meta: {} } ] // 没有layout布局的路由表 export const notLayoutRoutes = [ { path: '/login', component: Login, meta: {} } ] // 所有路由的配置项 export const configRoutes = layoutRoutes.concat(notLayoutRoutes)
3、src下新建utils/routesEach.js:传入路由表返回对应的组件,并且模拟vue中路由守卫
import React, { Fragment } from 'react' import { Switch, Redirect, Route } from 'react-router-dom' export default (routes) => { function routesEach(routeConfig) { return routeConfig.map((item) => { if (item.children) { return ( <Route path={item.path} key={item.path} render={() => { return ( <Fragment> <Route component={item.component}></Route> <Switch> <Redirect from={item.path} to={item.children[0].path} // 重定向到第一个路由 exact ></Redirect> {item.children.map((child) => { return ( <Route path={child.path} key={item.path} render={() => { return isAuthRequired(child) // 权限验证 }} ></Route> ) })} </Switch> </Fragment> ) }} ></Route> ) } else { return ( <Route path={item.path} key={item.path} render={() => { return isAuthRequired(item) }} ></Route> ) } }) } // 权限验证:路由守卫 function isAuthRequired(item) { // 先判断当前路由是否需要权限验证 if (item.meta.authRequired) { // 当前路由需要权限验证,判断token是否存在 if (localStorage.getItem('token')) { return <item.component></item.component> } else { return <Redirect to="/login"></Redirect> } } else { return <item.component></item.component> // 不需要权限验证的路由可以直接返回 } } return routesEach(routes) }
4、app.js