歡迎大家指導與討論 : )
一、前言
本文摘要:react-router的基本用法,動畫效果與路由,路由權限控制,路由離開確認,根據路由切分的按需加載,路由組件的屬性。本文是筆者在學習時整理的筆記,由於技術水平還不夠高,有錯誤的地方懇請各位指出,共同進步O(∩_∩)O
二、基本用法
二、1 路由定義(摘要: Router, Route)
在一個路由系統中,我們需要定義好路由表。我們需要用Router組件包含我們的路由表,通過Route來聲明單個的路由。同時,每個路由應該與它所屬的組件一一對應
render(( <Router >//開始創建路由表
<Route path="/" component={App}>//聲明每一個路由
<Route path="/about" component={About}/>
<Route path="users" component={Users}>//每個路由
<Route path=":id" component={User}/>//對應一個Component
</Route>
</Route>
</Router>
), document.getElementById('example'))
//其他定義路由表的方法
import routes from './config/routes'
render(<Router history={browserHistory} routes={routes}/>, document.getElementById('example'))
二、2 路由嵌套(摘要: IndexRouter, this.props.children)
如何實現路由的嵌套呢,與Angular路由一樣,路由的嵌套需要兩個條件。一、在創建路由表的時候就聲明好嵌套的規則(ng中的$stateProvider);二、需要有一個view來安放所要嵌套的子頁面(ng中的ui-view)。其中,我們還可以在嵌套層的首個路由聲明中,使用IndexRoute來聲明該路由下的默認路由(類似於ng中$urlProvider.otherwise)
//有嵌套與默認頁面的路由表
render(( <Router >
<Route path="/" component={App}>
<IndexRoute component={Index}/>//設置默認頁面
<Route path="/about" component={About}/>
<Route path="users" component={Users}>
<IndexRoute component={UsersIndex}/>//設置默認頁面
<Route path=":id" component={User}/>
</Route>
</Route>
</Router>
), document.getElementById('example')) //一個用於安放子頁(子路由)的view
class Users extends React.Component { render() { return ( <div>
<h2>Users</h2>
{this.props.children}//此處相當於<ui-view>
</div>
) } }
二、3 路由跳轉(摘要: Link,to)
我們需要一個Link組件幫助我們實現路由的的跳轉 <li><Link to="/users" >/users</Link></li> ,最終Link組件會被渲染為<a>標簽。to屬性是我們所要跳轉的路由pathname(類似於ng中的ui-sref / href)
二、3 . 1 父子路由的參數穿透傳遞(摘要: to = {`/xx/${xxx}/`} )
若父路由中包含不確定參數,而我們又想把該參數往下級傳遞,這時候我們需要這樣子做
//路由配置
<Route path="user/:userID" component={User}>
<Route path="tasks/:taskID" component={Task} />
<Redirect from="todos/:taskID" to="tasks/:taskID" />
</Route>
//子級路由
<li><Link to={`/user/${userID}/tasks/foo`} activeClassName="active">foo task</Link></li>
二、3 . 2 帶參數的路由跳轉
<li><Link to={{ pathname: '/users/ryan', query: { foo: 'bar' } }} activeStyle={ACTIVE}>/users/ryan?foo=bar</Link></li>
二、3 . 3 函數內跳轉(摘要: this.context.router.push('/'))
this.context.router.push('/') ,注:這個寫法會把跳轉載入瀏覽器歷史,若不想留下歷史記錄則可以 this.context.router.replace('/')
三、帶有動畫效果的路由切換(摘要: ReactCSSTransitionGroup)
當我們需要在路由切換時帶有一定的動畫效果時,我們便需要 react-addons-css-transition-group 這個插件了。使用ReactCSSTransitionGroup組件來包含我們需要呈現動畫效果的view
class App extends Component { render() { return ( <div>
<ul>
<li><Link to="/page1">Page 1</Link></li>
<li><Link to="/page2">Page 2</Link></li>
</ul>
<ReactCSSTransitionGroup component="div" transitionName="example" transitionEnterTimeout={500} transitionLeaveTimeout={500} > {React.cloneElement(this.props.children, { key: this.props.location.pathname })} </ReactCSSTransitionGroup>
//克隆所有子節點,單獨的{this.props.children}沒有動畫效果
</div>
) } }
四、路由的權限控制(摘要: onEnter、context.router)
單頁應用路由的權限控制的基本思路是:監聽路由的改變,每當路由將要發生改變,我們就使用一個中間服務(該服務介於上一級路由和將要到達路由之間啟動),來判斷我們是否有進入這個路由的權限,有的話直接進入,沒有的話就redirect。在React中,為某個路由進行權限監聽的方式是onEnter <Route path="page" component={Page} onEnter={requireCredentials}/> ,該onEnter屬性對應連着一個具有判斷權限的中間服務。我們通過上一級路由來啟動這個服務。假設我們需要從'/form'到'/page'之間做一個判斷,在'/form'中填寫特定字段后才能成功跳轉,否則redirect到'/error'
//form
const Form = createClass({ //省略部分代碼
submitAction(event) { event.preventDefault(); //通過context傳輸數據
//通過url的query字段傳輸數據
//也可以通過制定其他服務來傳輸數據
this.context.router.push({ pathname: '/page', query: { qsparam: this.state.value } }) }, render() { return ( <form onSubmit={this.submitAction}>
//省略部分代碼
<button type="submit">Submit </button>
</form>
) } }) //路由權限控制
<Route path="page" component={Page} onEnter={requireCredentials}/>
//權限控制的中間服務
function requireCredentials(nextState, replace, next) { //獲取傳輸過來的數據
if (query.qsparam) { serverAuth(query.qsparam) .then( () => next(),//成功,通過next()成功跳轉
() => { replace('/error')//重定向
next() } ) } else { replace('/error') next() } }
其中,onEnter所指向的函數是 type EnterHook = (nextState: RouterState, replace: RedirectFunction, callback?: Function) => any; 其中,nextState作為第一個參數,其所帶的信息有如下:
type RouterState = { location: Location; routes: Array<Route>; params: Params; components: Array<Component>; };
其中,replace函數一旦被使用到,則在函數內部跳轉到一個新url,返回時也要帶上必要的信息,如下
type RedirectFunction = (state: ?LocationState, pathname: Pathname | Path, query: ?Query) => void;
六、路由離開確認(摘要: componentWillMount, this.context.router.setRouteLeaveHook)
若我們需要在路由切換,在離開當前頁面的時候做一些確認工作,我們可以通過setRouteLeaveHook函數,為離開前執行一些操作
//Component內部
componentWillMount() { this.context.router.setRouteLeaveHook( this.props.route, this.routerWillLeave ) } routerWillLeave() { if (xxx) //...
},
七、根據路由按需加載組件
按需加載在單頁應用中的好處不言而喻,按業務模塊切分代碼能使首次加載資源所需要的時間大大降低,能在一定程度上增強用戶體驗。但首先我們需要整理一下我們的項目結構(此demo是按路由切分的,另外還能按業務模塊進行切分)
七 . 1 項目結構
七 . 2 路由表配置(app.js)
七 . 3 對應組件的加載配置(routes/hello/index.js和routes/test/index.js)
八、路由組件的屬性(摘要: this.props)
九、路由Location屬性
type Location = { pathname: Pathname; search: QueryString; query: Query; state: LocationState; action: Action; key: LocationKey; };