路由分为 HashRouter 和 BrowserRouter,HashRouter 是带有 # ,而 BrowserRouter 则没有
使用react-router的demo图如下:
步骤如下:
1 安装 react-router
npm install react-router-dom --save
2 引入这个 BrowserRouter (使用较多)
index.js中 ,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| import { BrowserRouter as Router, Route, Switch, Redirect } from "react-router-dom";
render( <Router> <> <App> <div className="content"> <Switch> <Route path="/" exact component={Home}></Route> <Route path="/activities" component={Activities}></Route> {} <PrivateRoute path="/topics" component={Topics}></PrivateRoute> <Route path="/login" component={Login}></Route> <Route path="/article/:id" component={Article}></Route> <Route path="/error.html" component={NoMatch}></Route> <Redirect to="/error.html"></Redirect> </Switch> </div> </App> </> </Router>, document.getElementById("root") );
|
注意:
1) exact:是完全匹配,一模一样才可以
2) switch:是匹配到一个就不会往下找了
3) Redirect:重定向
4) Router:只能有一个子元素
5) 这里是把Router这个组件放在了App组件里,当有东西放入一个组件中时可以这样做,但具体放在App
组件的哪里,可以在App组件中定义,{ this.props.children }
3 路由跳转用 Link、NavLink
可以抽离成一个组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| import React, { Component } from 'react'; import {Link,NavLink} from 'react-router-dom' import './nav.style.css'
class Nav extends Component { _handleClick = () => { console.log(this.props.history) this.props.history.push('/') } render () { return ( <div className="nav"> <span className="logo" onClick={this._handleClick}>大太阳LOGO</span> <NavLink to="/" exact>首页</NavLink> <NavLink to="/activities">动态</NavLink> <NavLink to="/topics">话题</NavLink> <NavLink to="/login">登陆</NavLink> </div> ) }
}
export default Nav;
|
注意:
1) Link 渲染的是a标签,它并不能改变渲染的是哪个元素,要想改变只能招别的方法
2) Link 对于当前选中的a标签并没有特殊的class 或是其他,但 NavLink 有
3) NavLink 除了对当前选中的a标签添加了 class :active,但其也是包含的关系,所以使用完全匹配,加上exact这个属性
4) 通过点击事件跳转的话,可以使用 this.props.history.push('/'
)`
4 二级路由
把二级路由也抽离成一个组件,activitiesnav.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| import React, { Component } from 'react'; import {NavLink} from 'react-router-dom'
class Activitiesnav extends Component {
render () { return ( <div> <NavLink to="/activities/recommended" exact>推荐</NavLink> <NavLink to="/activities/all">综合</NavLink> <NavLink to="/activities/articles">文章</NavLink> <NavLink to="/activities/pins">沸点</NavLink> </div> ) } }
export default Activitiesnav;
|
activities.js:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| render () { return ( <div> 动态 <Activitiesnav></Activitiesnav> <Switch> <Route path="/activities/recommended" exact component={ Recommended }></Route> <Route path="/activities/all" component={ All }></Route> <Route path="/activities/articles" component={ Articles }></Route> <Route path="/activities/pins" component={ Pins }></Route> <Redirect to="/activities/recommended"></Redirect> </Switch> </div> ) }
|
注意:尽量一个导航新建一个文件夹,如下:
5 动态路由
不通过Link这些区跳转,也就是在页面级组件中区跳转,在Route组件里(通过Route渲染出来的组件)有三个方法:props 、history、match,我们可以通过 this.props.history.push()
来实现跳转
6 withRouter
解决Link、NavLink只能渲染a标签的问题:
一:当我们不渲染成a标签的时候,此时不能使用Link、NavLink,跳转的功能我们只能通过click事件来处理,而此时 nav.js不是页面级组件,不能访问history,但我们可以在index.js中,用Route将这个Nav包裹起来,这是一个高阶组件(一个组件可以返回一个组件),但route是页面级组件用的,并不是说必须这样,只是说尽量页面级组件和导航这些分开,所以可以用 withRouter隔一层,nav.js:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| import React, { Component } from 'react'; import {NavLink, withRouter} from 'react-router-dom' import './nav.style.css'
class Nav extends Component { _handleClick = () => { console.log(this.props.history) this.props.history.push('/') } render () { return ( <div className="nav"> <span className="logo" onClick={this._handleClick}>大太阳LOGO</span> <NavLink to="/" exact>首页</NavLink> <NavLink to="/activities">动态</NavLink> <NavLink to="/topics">话题</NavLink> <NavLink to="/login">登陆</NavLink> </div> ) }
}
export default withRouter(Nav);
|
二:写一个组件,实现用span标签来渲染
menuLink.js:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import React from 'react' import {Route} from 'react-router-dom'
const MenuLink = ({to, ...props}) => { return ( <Route path={to} {...props} children={(p) => { return ( <span onClick={() => { p.history.push(to) }} className={p.match ? 'active': ''}> {props.children} </span> ) }}></Route> ) }
export default MenuLink
|
nav.js中这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| import React, { Component } from 'react'; import {NavLink, withRouter} from 'react-router-dom' import MenuLink from '../Menuink' import './nav.style.css'
class Nav extends Component { _handleClick = () => { console.log(this.props.history) this.props.history.push('/') } render () { return ( <div className="nav"> <span className="logo" onClick={this._handleClick}>大太阳LOGO</span> <MenuLink to="/" exact>首页</MenuLink> <MenuLink to="/activities">动态</MenuLink> <MenuLink to="/topics">话题</MenuLink> <MenuLink to="/login">登陆</MenuLink> </div> ) }
}
export default withRouter(Nav);
|
7 路由权限控制
在js中判断去哪,条件是否满足,条件满足之后去哪,没满足去哪,根据history match history以及其他方式来进行权限控制
当在进入某个路由时判断去哪时,可以把这部分的逻辑抽离出来,PrivateRoute.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| import React from 'react' import {Route, Redirect} from 'react-router-dom'
const PrivateRoute = ({component: Component, ...props}) => { return ( <Route {...props} render={(props) => { const isLogin = document.cookie.includes('login=true') if(isLogin) { return <Component></Component> }else { alert('还没有登陆,请先登陆') return <Redirect to={{ pathname: '/login', state: { from: props.location.pathname } }}></Redirect> } }}></Route> ) }
export default PrivateRoute
|
8 customLink
当离开某个页面时需要提示时采用,Prompt,如动态页面activities.js:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| import React, { Component } from 'react'; import { Route, Switch, Redirect, Prompt } from 'react-router-dom' import Activitiesnav from '../../allComp/activitiesnav/activitiesnav' import Recommended from './recommended/Recommended'; import All from './all/All'; import Articles from './articles/Articles'; import Pins from './pins/Pins';
class Activities extends Component {
render () { return ( <> <Prompt message={(location) => { const toPath = location.pathname.includes('/activities') if(toPath){ return true } return window.confirm('你确定要离开吗') }}/> <div> 动态 <Activitiesnav></Activitiesnav> <Switch> <Route path="/activities/recommended" exact component={ Recommended }></Route> <Route path="/activities/all" component={ All }></Route> <Route path="/activities/articles" component={ Articles }></Route> <Route path="/activities/pins" component={ Pins }></Route> <Redirect to="/activities/recommended"></Redirect> </Switch> </div> </> ) }
}
export default Activities;
|
注意:message为true,不会阻拦,为false,哪都去不了