橙子

react-router

路由分为 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>
{/* <Route path="/topics" component={Topics}></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 }

可以抽离成一个组件

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'

//withRouter 过程
// const withRouter = (Component) => () => <Route component={Component}></Route>

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'

//component 只去渲染一个组件,且路径要匹配
//render 与当前路径匹配才渲染,不匹配则不渲染
//children 与当前路径匹配才会有match

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'

// const withRouter = (Component) => () => <Route component={Component}></Route>

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

当离开某个页面时需要提示时采用,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,哪都去不了