摘要:
react-router相對於flux和redux來說,比較好容易理解一點和容易入門一點。這個是根據我之前的一個項目,然后我用react+react-router+webpack重新寫的。
不過沒有全部寫完。只寫了一部分。不過用來實戰已經足夠了。
不過由於這個項目我主要是用來學習react-router,所有有些地方沒必要用路由的我還是用了。所以如果要拿去用,這點要注意。
還有就是這個demo不是很完善,需要自己去完善一下。尤其是一些目錄結構,由於當時沒考慮好。所以可以稍加完善
注意點:此demo是根據react-router 1.0版本來寫的。之前版本的用法我沒有學過,是直接就學這個版本的。所以如果語法上跟各位的有區別的話,那應該是版本不同所導致的。
當然,大家學習的話應該最好也以1.0版本來學,因為1.0版本相對來說是比較新和穩定的。而且拋棄了很多以前舊的語法,所以和以前版本的語法是有點區別的。目前好像正在出2.0了。技術的更新真的不是一般的快啊
為什么要用路由?
個人理解的話,就前端而言,路由還是因為單頁面應用時代的帶來而衍生出來的。當url發生變化時,路由相應的做出一些相應,從而來保證目前的url和要展示的界面一一對應好。
效果圖如下:類似於微商城的一個網頁。點擊頁腳的不同位置,可以切換不同的頁面。
demo地址:https://github.com/xianyulaodi/React-router
入口文件: render/app.js
1 import React from 'react' 2 import { render } from 'react-dom' 3 import { Router, Route, IndexRoute, Link, IndexLink } from 'react-router' 4 import { createHistory, useBasename } from 'history' 5 6 7 import App from '../component/app.js' 8 import Mall from '../component/routers/mall/mall.js' 9 import Circle from '../component/routers/circle/circle.js' 10 import CircleType from '../component/routers/circle/circleType.js' 11 import My from '../component/routers/my/my.js' 12 import MyNav from '../component/routers/my/myNav.js' 13 import MyUserCenter from '../component/routers/my/userCenter.js' 14 import MemberClub from '../component/routers/my/memberClub.js' 15 import Index from '../component/routers/index/index.js' 16 import Type from '../component/routers/index/type.js' 17 import CircleTip from '../component/routers/circle/circleTip.js' 18 import CircleSay from '../component/routers/circle/circleSay.js' 19 20 const history = useBasename(createHistory)({ 21 basename: '/React-Router' 22 }); 23 24 {/** {this.props.children} 非常重要**/} 25 {/** 思考:首頁也有其他分路由,怎么配**/ } 26 render(( 27 <Router> 28 <Route path="/" component={App}> 29 <IndexRoute component={Index} /> 30 31 <Route path="/type/:typeName" component={Type} /> 32 33 <Route path="/mall" component={Mall}> 34 <Route path="type/:typeName" component={Type} /> 35 </Route> 36 37 <Route path="/my" component={My}> 38 <IndexRoute component={MyNav} /> 39 <Route path="userCenter" component={MyUserCenter} /> 40 <Route path="memberClub" component={MemberClub} /> 41 </Route> 42 43 <Route path="/circle" component={Circle}> 44 <IndexRoute component={CircleType} /> 45 <Route path="tip/:tipName" component={CircleTip} /> 46 <Route path="say" component={CircleSay} /> 47 </Route> 48 49 </Route> 50 </Router> 51 ), document.getElementById('index'))
基本上所有的文件都集中在這里了。所以這個文件是入口文件,通過不同的hash值來調用不同的組件,從而讓url的變化和界面的變化相對應。
這里將一個個的介紹react-router屬性的作用。這里的介紹花的篇幅可能會比較多,因為搞懂了這里,也就基本搞懂react-router了。
1、<Route path="/" component={App}>
這一句是所有路由的父集,也就是最高級的位置。路由里面的東西為什么可以換來換去呢。就是在這個組件里面來切換的;
這個app里面的核心代碼如下: .. /component/app.js //這里是./component/app 和 ./render/app.js是兩個不同的文件來的 !!!
return ( <div className="mp_wrap bui_wrap"> {/**主屏幕**/} <div className="mp_pagebox_home"> {/**這里面的內容會被子路由給代替**/} {this.props.children} {/**公共頁腳**/} <div className="mp_page_footer"> <Footer /> </div> {/**公共頁腳**/} </div> {/**主屏幕**/} </div> )
里面的 {this.props.children} 這句話是核心。它告訴頁面,它的子集都在這里展示。所以,每次我們點擊切換不同的url,看到不同內容的變化,
其實是這里面一直替換來替換去而已。沒有替換掉的就是那個Footer組件,因為那個是頁腳用來導航的:
里面的代碼如下:(代碼被簡化,具體看源碼)
./component/router/publicComponent/footer.js
1 const Footer = React.createClass({ 2 3 render: function() { 4 5 return ( 6 <div className="bui_avg_sm_4 bui_ta_c bui_bgc_lgray bui_ptb_6" > 7 {/**使用IndexLink,可以讓首頁的鏈接不會一直處於激活狀態**/} 8 <IndexLink to="/" styles={styles.link} activeStyle={styles.activeLink}>教程</IndexLink > 9 <Link to="/circle" styles={styles.link} activeStyle={styles.activeLink}>烘培圈</Link> 10 <Link to="/mall" styles={styles.link} activeStyle={styles.activeLink}>商城</Link> 11 <Link to="/my" styles={styles.link} activeStyle={styles.activeLink}>我的</Link> 12 </div> 13 ); 14 15 } 16 })
這里通過reac-router提供的Link來進行路徑的跳轉。
這里有個注意點:IndexLink,就是默認顯示哪個鏈接高亮,不然的話默認的首頁的鏈接狀態就一直處於高亮狀態。通過style,以及activeStyle來切換高亮時的樣式
2、IndexRoute的作用
想象一下當 URL 為 /
時,我們想渲染一個在 App
中的組件。不過在此時,App
的 render
中的this.props.children
還是 undefined,也就是說里面是空的。
所以我們要讓它默認顯示首頁的信息
。這種情況我們可以使用 IndexRoute
來設置一個默認頁面。
看什么的29行代碼:
<Route path="/" component={App}>
<IndexRoute component={Index} />
可以看看這里的代碼,讓url沒有鏈接到其他路由時,默認顯示Index這個組件里面的內容
3、路由匹配原理 :
嵌套關系:
中文網的解釋:React Router 使用路由嵌套的概念來讓你定義 view 的嵌套集合,當一個給定的 URL 被調用時,整個集合中(命中的部分)都會被渲染。
嵌套路由被描述成一種樹形結構。React Router 會深度優先遍歷整個理由配置來尋找一個與給定的 URL 相匹配的路由。
什么意思呢。上面的入口文件中,可以看到,其他路由都是最外層那個app(也就是這個<Route path="/" component={App}>)的子路由,其他路由都是嵌套在這里面。
當url變化是,它里面的{this.props.children}都會替換,也就是所謂的整個集合的命中部分都會被渲染。
路徑語法:
中文網原文:
路由路徑是匹配一個(或一部分)URL 的 一個字符串模式。大部分的路由路徑都可以直接按照字面量理解,除了以下幾個特殊的符號:
:paramName
– 匹配一段位於/
、?
或#
之后的 URL。 命中的部分將被作為一個參數()
– 在它內部的內容被認為是可選的*
– 匹配任意字符(非貪婪的)直到命中下一個字符或者整個 URL 的末尾,並創建一個splat
參數
<Route path="/hello/:name"> // 匹配 /hello/michael 和 /hello/ryan <Route path="/hello(/:name)"> // 匹配 /hello, /hello/michael 和 /hello/ryan <Route path="/files/*.*"> // 匹配 /files/hello.jpg 和 /files/path/to/hello.jpg
如果一個路由使用了相對路徑
,那么完整的路徑將由它的所有祖先節點的路徑
和自身指定的相對路徑
拼接而成。使用絕對路徑
可以使路由匹配行為忽略嵌套關系。
聽起來比較頭暈,可以這樣理解,就是正常的url匹配模式就是一條 斜線+路勁名。比如跳到個人中心 <Route path="/my" component={My}>,如果要傳值:就類似這樣 <Route path="tip/:tipName" component={CircleTip} />
其實就這樣理解就行了。不然會把自己搞的很暈。
繼續前面的入口文件 render/app.js
通過前面的了解,我們的頁面在最開始的url的時候有了一個默認的組件 index,當我們要跳轉的時候,我們可以通過url的不同來調用不同的組件。
比如個人中心,<Route path="/my" component={My}>,當識別到你的url是/my 時,就調用My這個組件。
可以看下圖:方框內,不同路由就把對應的里面的內容給替換掉。
子路由下還有子路由的情況
如果在my這個路徑下,我還有子路由怎么辦呢?就像點擊我的頁面,點擊頭像,可以跳轉到個人中心那種。方法如下:
<Route path="/my" component={My}> <IndexRoute component={MyNav} /> <Route path="userCenter" component={MyUserCenter} /> <Route path="memberClub" component={MemberClub} /> </Route>
在my這個路徑下,我還有userCenter,memberClub。比如你點擊頭像,就會跳轉到這樣的url http://localhost:3200/#/my/userCenter?_k=t18l2p
{My} 這個組件的內容如下:
var Content= React.createClass({ render(){ return ( <div> {this.props.children} </div> ) } }) module.exports= Content
里面的{this,props.children}也是注意點。用來替換它子組件的內容。可以這么理解,只要你是父組件,都有一個 {this.props.children}來裝載替換子組件的內容
注意點:
因為/my是父路由,所以它的寫法跟最外層的app那個路由時類似的,所以也要設置一個默認顯示的頁面,也就是IndexRouter。
這里我就默認顯示MyNav這個組件,不然里面是什么都沒有的。這點初學時會經常忘記。切記切記!!!
路由之間參數的傳參:
為了演示參數的傳遞,我將一個tab的切換弄成了路由之前的傳值,實際應用中沒有必要。只是為了演示而已,在./render/app.js的第31行
<Route path="/type/:typeName" component={Type} />
跳轉到了/type/:typeName這里,並調用對應的{Type}組件,為它傳了一個typeName的值,所以我們在傳值時可以這樣
在跳轉到type時,后面着一個你要傳遞的值。
<Link to="/type/餅干"> <p className="icon icon1"></p> <p className="bui_ta_c bui_tc_gray">餅干</p> </Link>
那我要獲取到傳遞的值怎樣做呢,可以這樣,在{Type}組件中。
const { typeName } = this.props.params
其中params就是參數的意思。這樣我們就可以在需要使用參數的地方來使用我們的參數了。
暫時就介紹到這里了。主要是搞懂了./render/app.js里面的內容和相對應的一些知識,也就基本搞懂路由了。其他地方的用法都是類似的。
參考鏈接:
react-router中文網:http://react-guide.github.io/react-router-cn/docs/guides/basics/RouteMatching.html
備注:再次強調一下,我的這個實戰目錄結構不好,如需拿去項目中使用,記得把項目結構建好一點。另外,有誤指出,歡迎指出。多多交流