路由理解
当使用 hash
或 history
的方式去改变网址路径(path)
时,并不会刷新网页或发出请求
通过监听 hash
或 history
的变化来动态的切换组件的显示
据此,可以维护 path(路径)
跟 component(组件)
的 一对一的路由
而管理这些route(路由)
的就是router(路由器)
路由步骤
路由的实现,是基于BOM的history,从而实现网页不刷新,局部更新页面。
- 点击导航链接,引起路径变化
- 路径变化,被路由器检测到,进行组件匹配,从而被展示
安装
yarn add react-router-dom
注意:不要忘记-dom(区分于vue的vue-touer)
简单DEMO
- index.js
import React from 'react'
import ReactDOM from 'react-dom'
import {BrowserRouter} from 'react-router-dom'
import App from './App'
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>
, document.getElementById('root'))
- App.js
import React, { Component } from 'react'
import { Link, Route } from 'react-router-dom'
import About from './components/About'
import Home from './components/Home'
export default class App extends Component {
render() {
return (
<div>
<div className="row">
<div className="col-xs-offset-2 col-xs-8">
<div className="page-header"><h2>React Router Demo</h2></div>
</div>
</div>
<div className="row">
<div className="col-xs-2 col-xs-offset-2">
<div className="list-group">
{/* <a className="list-group-item" href="./about.html">About</a>
<a className="list-group-item active" href="./home.html">Home</a> */}
<Link className="list-group-item" to="/home">Home</Link>
<Link className="list-group-item" to="/about">About</Link>
</div>
</div>
<div className="col-xs-6">
<div className="panel">
<div className="panel-body">
<Route path="/home" component={About}></Route>
<Route path="/about" component={Home}></Route>
</div>
</div>
</div>
</div>
</div>
)
}
}
- Home/index.jsx
import React, { Component } from 'react'
export default class Home extends Component {
render() {
return (
<div>
<h3>我是Home的内容</h3>
</div>
)
}
}
- About/index.jsx
import React, { Component } from 'react'
export default class About extends Component {
render() {
return (
<div>
<h3>我是About的内容</h3>
</div>
)
}
}
路由的基本使用注意事项
-
明确好界面中的导航区、展示区
-
导航区的
a
标签改为Link
标签
<Link to="/xxxxx">Demo</Link>
- 展示区写Route标签进行路径的匹配
<Route path='/xxxx' component={Demo}/>
- 组件APP的使用处,即
<App >
的最外侧包裹了一个<BrowserRouter>
或<HashRouter>
路由标签
Link
用于更改path
Route
用于注册路由BrowserRouter
为history
模式路由器,需要包裹在App
标签外,以保证所有路由都受它管理HashRouter
为hash
模式路由器,需要包裹在App
标签外,以保证所有路由都受它管理NavLink
: 相比于Link
, 在激活时会应用active
类名,该类名可以通过activeClassName
属性进行指定
<NavLink activeClassName="active" path="/about" component={About}>About</NavLink>
//当该link被点击时,会在类中添加一个 active类,从而实现样式的添加
Switch
: 选择路由时,匹配成功就停止不再继续向下匹配,如下
<!-- 如果当前 路径为 /home 那么最后两个组件都会被显示 -->
<Route path="/about" component={About} />
<Route path="/home" component={Home} />
<Route path="/home" component={Home} />
<!-- 如果使用 Switch 包裹路由 那么在第一次成功匹配后,就不会再继续向下匹配,因此只显示第二个组件-->
<Switch>
<Route path="/about" component={About} />
<Route path="/home" component={Home} />
<Route path="/home" component={Home} />
</Switch>
//1.通常情况下,path和component是一一对应的关系。
//2.Switch可以提高路由匹配效率(单一匹配)。
Redirect
: 重定向,一般写在所有路由注册的最下方,当所有路由都无法匹配时,跳转到Redirect指定的路由
<Switch>
<Route path="/about" component={About} />
<Route path="/home" component={Home} />
<!-- 当其他路由都匹配不上时,将当前路由路径重定向到 /home -->
<Redirect to="/home" />
</Switch>
- todos 待补充
严格匹配跟模糊匹配
- 默认使用的是模糊匹配(简单记:【输入的路径】必须包含要【匹配的路径】(即Link中的路径要完全包含route中对应的路径),且顺序要一致)
- 假设当前路由路径是
/home/a/b/c
,那么 以下路由会显示,因为/home
模糊匹配成功
<Route path="/home" component={Home} />
- 开启严格匹配:
- 而如果开启
严格匹配(指定exact)
,则必须路由路径完全相同
<Route exact path="/home" component={Home} /> // 不显示
<Route exact path="/home/a/b/c" component={Home} /> // 显示
- 严格匹配不要随便开启,需要再开,有些时候开启会导致无法继续匹配二级路由
路由嵌套
- 当使用多级嵌套路由时,子路由的路径,需要包含父级的路径
- 每当路由路径发生变化时,
react
都会从最开始注册的路由,到最后注册的路由,依次进行匹配
<Route path="/home/news" component={news} />
路由组件与一般组件
- 写法不同:
一般组件:<Demo/>
路由组件:<Route path="/demo" component={Demo}/>
-
存放位置不同:
一般组件:components
路由组件:pages -
接收到的props不同:
一般组件:写组件标签时传递了什么,就能收到什么
路由组件:接收到三个固定的属性
路由导航模式
- 路由有两种导航方式: push、replace
- 默认情况是 push 方式, 可以使用如下方式修改为 replace
<Link replace to="/home/news">news</Link>
编程式路由导航
- 借助
this.props.history
上的方法进行导航(注意区分,路由组件所独有的history属性)
this.props.history.push(pathname, state)
this.props.history.replace(pathname, state)
this.props.history.go(n)
this.props.history.goBack()
this.props.history.goForward()
withRouter
- 一般组件在 this.props 没有 history对象,因此无法直接通过history进行push、replace等方法的调用
- 因此,可以使用 withRouter 函数,对一般组件进行包装,使其拥有路由组件的方法和属性
import {withRouter} from 'react-router-dom'
class Header extends Component {
...
}
export default withRouter(Header) // 导出包装后的对象