react-router
React路由哩盲,讓父組件動(dòng)態(tài)去掛載不同的子組件沿后,本文以4.x
為例闷游;
4.x
對(duì)依賴包的劃分:
-
react-router
路由基礎(chǔ)庫(kù) -
react-router-dom
適用于瀏覽器環(huán)境的再次封裝 -
react-router-native
適用于原生開發(fā)環(huán)境的再次封裝 -
react-router-config
靜態(tài)路由配置助手
v4
與v5
用法差不多惊奇,但與v2/v3
差異較大,v4/v5
采用的是動(dòng)態(tài)路由开仰,而v2/v3
采用的是靜態(tài)路由拟枚。
v5 新增了一些新特性薪铜,向后兼容:
- 消除了嚴(yán)格模式的警告
- 對(duì)
react v16
有了更好的支持 - 升級(jí)了
react context api
- 預(yù)優(yōu)化
build
,無(wú)需考慮生產(chǎn)環(huán)境和開發(fā)環(huán)境
react-router
主張 一切皆組件梨州,不像vue-router
那樣做中心化配置(集中式路由)痕囱。當(dāng)然眶根,react也支持集中式路由呛牲。
- 前端路由的實(shí)現(xiàn):
history
庫(kù),管理瀏覽器會(huì)話歷史的工具庫(kù)沼瘫。本質(zhì)上還是包裝了原生BOM中的window.history
和window.location.hash
- 核心組件:
<BrowserRouter>每窖、<HashRouter>帮掉、<Route>、<Redirect>窒典、<Link>蟆炊、<NavLink>、<Switch>
-
Hash
模式:<HashRouter> -
HTML5:history
模式:<BrowserRouter> -
react native
開發(fā)使用的是MemoryHistory
-
- 對(duì)象:
history瀑志、match涩搓、withRouter
引入路由之后,可以把組件分為兩類:普通組件(components
目錄)劈猪、路由組件(views
目錄)
基本配置
- 安裝
react-router-dom
模塊:npm install react-router-dom -S
- 在根組件
App.js
中引入路由相關(guān)的組件昧甘,加載的子組件包括Home.js、News.js战得、Product.js充边、NotFound.js
import { BrowserRouter, Route, NavLink, Switch } from 'react-router-dom' render() { return(<BrowserRouter> <div> <header> <NavLink to="/">首頁(yè)</NavLink> <NavLink to="/news">新聞</NavLink> <NavLink to="/product">商品</NavLink> <NavLink to="/notfound">一個(gè)不存在的路由</NavLink> </header> <Switch> <Route exact path="/" component={Home} /> <Route path="/news" component={News} /> <Route path="/product" component={Product} /> <Route component={NotFound} /> // 404組件 </Switch> </div> </BrowserRouter>) }
- 在根組件中,把Home組件的路由配置為
path="/"
常侦,表示默認(rèn)加載Home組件浇冰; -
exact
:表示嚴(yán)格匹配模式,必須完全匹配聋亡,如果設(shè)置為false
肘习,每次都會(huì)匹配path="/"
的路由; - 404組件不需要聲明任何
path
坡倔,且必須放在最后面漂佩,當(dāng)上面的所有路由都沒(méi)有匹配時(shí),則匹配404路由致讥。
- 在根組件中,把Home組件的路由配置為
-
Redirect
表示重定向仅仆,可用于指定默認(rèn)路由import { BrowserRouter, Route, NavLink, Switch, Redirect } from 'react-router-dom' render() { return(<BrowserRouter> <div> <header> <NavLink to="/">首頁(yè)</NavLink> <NavLink to="/news">新聞</NavLink> <NavLink to="/product">商品</NavLink> </header> <Switch> <Route path="/home" component={Home} /> <Route path="/news" component={News} /> <Route path="/product" component={Product} /> <Redirect to="/home" /> //默認(rèn)路由器赞,加載Home組件 </Switch> </div> </BrowserRouter>) }
- 一個(gè)項(xiàng)目中只有一個(gè)
<BrowserRouter>
垢袱,所以<BrowserRouter>
包裹根組件即可! -
<NavLink>
和<Route>
必須包裹在<BrowserRouter>
中港柜,且<BrowserRouter>
只能有一個(gè)直接子節(jié)點(diǎn)请契; -
NavLink
與Link
:它們最終都被解析為HTML
中的<a>
咳榜,但內(nèi)部會(huì)阻止瀏覽器的默認(rèn)行為;-
to
屬性用于指定跳轉(zhuǎn)的路由爽锥,也可以是一個(gè)對(duì)象<Link to={{ pathname: '/courses', search: '?sort=name', hash: '#the-hash', state: { fromDashboard: true } }}/>
-
<NavLink>
是<Link>
的一個(gè)特定版本涌韩,它會(huì)在匹配上當(dāng)前的url
時(shí)給已經(jīng)渲染的元素添加參數(shù); -
<NavLink>
上的屬性:activeClassName氯夷、activeStyle臣樱、exact、strict ...
<NavLink className="normal" activeClassName="active" to="/news"> //NavLink的默認(rèn)樣式className=""腮考,匹配時(shí)的激活樣式:activeClassName="" 或 activeStyle={}
- 自定義
NavLink
:MyNavLink.jsx
雇毫,統(tǒng)一使用一個(gè)activeClassName
import React, {Component} from 'react' import {NavLink} from 'react-router-dom' export default class MyNavLink extends Component { render() { return <NavLink {...this.props} activeClassName='active'> } }
-
-
Route
:path
指定路由,component
指定路由對(duì)應(yīng)的組件踩蔚; -
Switch
:從上往下匹配時(shí)棚放,只要匹配成功,就不會(huì)再向下匹配馅闽,即只顯示與當(dāng)前路由匹配的Route
飘蚯; -
<NavLink>
和<Route>
可以不在同一個(gè)組件中,只要路由匹配福也,都可以實(shí)現(xiàn)路由跳轉(zhuǎn)局骤。
路由傳值
- 動(dòng)態(tài)路由傳參:
<Route path="/info/:id" component={Info} />
this.state = { id:12 }
-
:id
表示占位符,對(duì)應(yīng)的NavLink
:<NavLink to={`/info/${this.state.id}`}>詳情</NavLink>
- 在
Info.js
組件中獲取動(dòng)態(tài)路由的參數(shù)id
:this.props.match.params
componentDidMount() { let { id } = this.props.match.params }
-
-
GET
方式傳參<Route path="/info" component={Info} /> <NavLink to={`/info?id=${this.state.id}`}>詳情</NavLink>
- 在
Info.js
組件中拟杉,獲取參數(shù)的對(duì)象:this.props.location
const { search } = this.props.location
- 但是庄涡,GET參數(shù)并沒(méi)有被解析,仍是一個(gè)原始字符串:
?id=12
- 借助第三方模塊url解析get參數(shù):
npm install url --save
import url from 'url' //url模塊是node上的內(nèi)置模塊搬设,npm上的url模塊并不是node的 componentDidMount() { let { id } = url.parse(this.props.location.search, true).query }
- React不建議使用
?xxx=xxx
的方式傳參穴店,而是把to
設(shè)置為對(duì)象<NavLink to={ { pathname:'/info', id:this.state.id } }>詳情</NavLink>
- 在
- React解析原始HTML字符串:
dangerouslySetInnerHTML
屬性this.state = { content: '<p>原始HTML字符串</p>' } <div dangerouslySetInnerHTML={{__html: this.state.content}}></div>
路由嵌套
-
User.js
組件是根路由App.js
的動(dòng)態(tài)子組件,路由名稱為/user
- 在
User
組件中再配置兩個(gè)動(dòng)態(tài)子組件:Main.js
和Info.js
import { Route, NavLink, Redirect, Switch } from 'react-router-dom' render() { return(<div> <div className="left"> <NavLink to="/user/">個(gè)人中心</NavLink> <NavLink to="/user/info">用戶詳情</NavLink> </div> <div className="right"> <Switch> <Route exact path="/user/" component={Main} /> <Route path="/user/info" component={Info} /> <Switch> </div> </div>) }
-
User
組件的路由為/user
拿穴,則把子組件Main的路由設(shè)置為/user/
泣洞,表示默認(rèn)加載Main
組件; - 亦或者,
Redirect
重定向的方式實(shí)現(xiàn)默認(rèn)加載的路由組件render() { return(<div> <div className="left"> <NavLink to="/user/center">個(gè)人中心</NavLink> <NavLink to="/user/info">用戶詳情</NavLink> </div> <div className="right"> <Switch> <Route exact path="/user/center" component={Main} /> <Route path="/user/info" component={Info} /> <Redirect to='/user/center' /> <Switch> </div> </div>) }
-
Redirect
的to
屬性也可以是一個(gè)對(duì)象:pathname
表示路由地址默色,其他的是參數(shù)球凰;<Redirect to={ {pathname:'/', state:{foo:'bar'}} } />
- 在
- 動(dòng)態(tài)獲取父級(jí)的路由,再拼接成自己組件的路由
<Route exact path={`${this.props.match.url}/`} component={Main} /> <Route path={`${this.props.match.url}/info`} component={Info} />
JS控制路由跳轉(zhuǎn)
- 借助對(duì)象:
this.props.history
中的方法 -
push()腿宰、replace()呕诉、goBack()、goForward() ......
this.props.history.push('/home/user'); this.props.history.push({ pathname: '/home/user', state: { foo:'bar' } });
- 獲取傳遞的參數(shù):
this.props.location
const { foo } = this.props.location.state;
路由守衛(wèi)
- 路由守衛(wèi)其實(shí)就是路由攔截吃度,可以做權(quán)限控制甩挫,它其實(shí)也是一個(gè)組件,返回值是一個(gè)
Route
組件椿每;
class RouteGuard extends Component {
state = {
isLogin: false
}
render() {
const {component:Component, ...otherProps} = this.props
return (
<Route {...otherProps} render={props => (
//只有已經(jīng)登錄了才允許進(jìn)入守衛(wèi)路由對(duì)應(yīng)的組件伊者,沒(méi)有登錄則重定向到登錄頁(yè)
this.state.isLogin ? <Component {...props}></Component> :
(<Redirect to={{ pathname:'/login', state:{from:props.location.pathname} }} />)
)}></Route>
)
}
}
- 在需要控制權(quán)限的地方英遭,應(yīng)用路由守衛(wèi)
render() {
return(<BrowserRouter>
<div>
<header>
<NavLink to="/">首頁(yè)</NavLink>
<NavLink to="/news">新聞</NavLink>
<NavLink to="/mine">我的</NavLink>
</header>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/news" component={News} />
<RouteGuard path="/mine" component={Mine} /> // 應(yīng)用路由守衛(wèi)
</Switch>
</div>
</BrowserRouter>)
}
路由的模塊化
- 用一個(gè)數(shù)組管理項(xiàng)目中的所有路由,在把這個(gè)數(shù)組放在一個(gè)獨(dú)立的
JS
文件中- 在
router.js
中引入相關(guān)組件亦渗,管理路由const routes = [ { path:'/', component:Home, exact:true }, { path:'/user', component:User } ] export default routes;
- 在根組件
App
中引入路由模塊import routes from './route/router.js' render(){ return(<BrowserRouter> <header> <NavLink to="/">首頁(yè)</NavLink> <NavLink to="/user">用戶</NavLink> </header> { routes.map((route, key) => { if(route.exact) { return <Route key={key} exact path={route.path} component={route.component} /> } else { return <Route key={key} path={route.path} component={route.component} /> } }) } </BrowserRouter>) }
- 在
- 嵌套路由的管理
- 在
router.js
中const routes = [ { path:'/', component:Home, exact:true }, { path:'/user', component:User, routes:[ { path:'/user/', component:Main }, { path:'/user/info', component:Info } ] } ]
- 在根組件
App
中挖诸,通過(guò)<Route>
的render
屬性,把子路由傳遞給子組件<Route key={key} path={route.path} render={props => ( <route.component {...props} routes={route.routes} /> )} />
- 在
User
組件中獲取子路由:this.props.routes
render() { return(<div> <div className="left"> <NavLink to="/user/">個(gè)人中心</NavLink> <NavLink to="/user/info">用戶詳情</NavLink> </div> <div className="right"> { this.props.routes.map((route, key) => { return <Route key={key} exact path={route.path} component={route.component} /> }) } </div> </div>) }
- 在
- 子路由的
<Route />
上可以都加上exact
屬性法精,而根路由的<Route />
上不行多律!