這是我參與8月更文挑戰的第3天,活動詳情查看:8月更文挑戰css
即單頁面web(single page web application)
應用。整個應用只有一個完整的頁面,點擊頁面中的連接不會刷新頁面,只會作頁面的局部更新。數據都須要經過ajax
獲取。html
也就是說,正由於有了路由這個技術的存在,才能實現咱們在同一個頁面中進行局部刷新(單頁面多組件)。前端
一個路由就是一個映射關係(key: value)node
key爲路徑,value多是function(後端路由) 或 component(前端路由);react
後端路由:註冊:router.get(path, function(req, res))
。當node接收到一個請求時,根據請求路徑找到匹配的路由,調用路由中的函數來處理請求,返回響應數據。web
前端路由:註冊:Route path="/test" component={Test}
。用於展現頁面內容。當瀏覽器的path變爲/test時,當前路由組件就會變成Test組件。好比對於一個在127.0.0.1:3000
的頁面,當它爲127.0.0.1:3000/home
(而不是/home.html
)顯示的就是home組件。ajax
好比下圖這個案例,切換的就是頁面,而不是組件。(下面會有此案例同個頁面多個組件的寫法)後端
首先要認識一下react的一個的插件庫react-router-dom
(須要手動下載),該庫專門用來實現一個SPA應用,基於react的項目基本都會用到它。瀏覽器
在咱們以前的學習BOM
中,是有一個history方法的,在這裏咱們經過引入一個history
的js
文件直接調用歷史記錄的一些方法。瀏覽器的歷史記錄是一個棧的結構。markdown
<script src="https://cdn.bootcss.com/history/4.7.2/history.js"></script>
let history = History.createBrowerHistory(); // 直接使用H5推出的history的API
// let history = History.createBrowerHistory(); hash值 錨點跳轉(多了個#)
function push(path) {
history.push(path); // 入棧
}
function replace(path) {
history.replace(path); // 替代棧頂元素
}
function back() {
history.goBack(); // 回退
}
function forward() {
history.goForward(); // 前進
}
history.listen(location)=> { // 監聽路徑變化
console.log(location);
}
複製代碼
接下來實現上面那個案例。在原生js
中是經過<a>標籤
跳轉到不一樣的頁面,而在react中,是靠路由連接<Link><link/>
實現切換組件的(編寫路由連接)。注意:這裏的Link
是從react-router-dom
庫裏面拿的。在組件分別展現的時候須要註冊路由route
。
基本步驟:(1)確認界面中的導航區、展現區;(2)導航區的a標籤
改成Link標籤
;(3)展現區的Route標籤進行路徑的匹配;(4)在<App>
的最外側包裹一個<BrowserRouter>
或者<HashRouter>
// App.jsx
import { Link, BrowserRouter, Route } from 'react-router-dom' // 引入react-router-dom庫
// 編寫路由連接
<Link className="list-group-item" to="/about">About</Link>
<Link className="list-group-item" to="/home">Home</Link>
// 註冊路由
<Route path="/about" component={About}></Route>
<Route path="/home" component={Home}></Route>
複製代碼
路由在使用的時候,須要在外層中包裹一層<BrowserRouter><BrowserRouter/>
,至關於一個路由器,管理裏面的東西。並且只能有一個路由器,不能寫2個,不然就至關於兩個路由器,兩個路由器之間是沒有數據溝通的。所以能夠在App
組件渲染的時候,在其外層放路由器。即
// index.js
ReactDOM.render(
<BrowserRouter> <App /> </BrowserRouter>,
document.getElementById('root')
);
複製代碼
這樣子就能夠實現一個SPA了。此時能夠看到頁面路徑發生了變化,並且<Link>
標籤渲染到瀏覽器中實際上是轉換爲<a>
標籤的,而to
轉換爲href
(轉換爲瀏覽器認識的標籤)。可是是組件的展現而不是頁面之間的跳轉(沒有.html
後綴),打開控制檯的network
也能夠看到此時的瀏覽器並無發送請求。
若是想要加上上面那個案例的高亮效果,把Link
改爲NavLink
便可(記得從react-router-dom
中引入)。默認點擊的時候默認給active
樣式,可是若是想要給的樣式名不是active
,那就須要加一個activeClassName="..."
(這個的默認值是active)
<NavLink activeClassName="home" className="list-group-item" to="/home">Home</NavLink>
//至關於
<NavLink activeClassName="home" className="list-group-item" to="/home" children="Home"></NavLink>
複製代碼
總結:NavLink
能夠實現路由連接的高亮,經過activeClassName
指定樣式名,標籤體內容是一個特殊的標籤屬性,經過this.props.children
能夠獲取到標籤體內容。
上面這種組件就是路由組件,那麼它和普通組件還有什麼區別呢?
寫法不一樣。通常組件:直接寫組件標籤:<home/>
;
路由組件:<Route path="/about" component={Home}></Route>
存放位置不一樣。通常組件放在components
;路由組件通常放在pages
中。
接收到的props
不一樣。通常組件:給它傳遞什麼就收到什麼;路由組件:接收到3個固定屬性
對於路由組件,咱們打印出它的props
屬性,這裏在用這個組件的時候並無給它傳值,可是它會有自帶的props
(history
、location
、match
)其中history.location=location
。而對於普通組件,若是沒有給它傳值,它打印出來的props
就是空的。
上面說的是路由的基礎使用,接下來講一說在路由中是怎麼進行組件之間的傳參的。
傳遞params參數
在路由組件傳遞參數的時候,在Link中傳遞參數,要在註冊的路由將這些參數讓Detail接收,採用下面這種方式。此時在Detail組件中打印this.props
的話就能夠在this.props.match.params
裏面看到咱們經過Link傳遞過去的參數。
<Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link>
<Route path="/home/message/detail/:id/:title" component={Detail}></Route>
複製代碼
傳遞search參數
search參數在傳遞的時候形式以下。並且search不用在註冊路由的時候接收參數,直接註冊便可,在this.props.location.search
中就能夠找到傳遞的參數,不過在這裏傳遞的對象是?key=value&key=value
,咱們要手動改爲{key: value;}
的形式;
可使用引入內置庫import qs from queryString
,再用qs.parse(search)
來處理從this.props
中獲得的search
對象(注意:用parse以後前面仍是會有一個?
,用slice(1)
截掉便可
<Link to={`/home/message/detail/?id=${msgObj.id}&title=${msgObj.title}`}>{msgObj.title}</Link>
複製代碼
state參數
上面說的params參數和search參數在傳遞參數的時候都會將傳遞的鍵值對暴露在地址欄上;state和search同樣,不用聲明接收,直接註冊便可;傳遞參數方式以下(傳對象);
傳遞以後在this.props.location.state
裏面就能夠找到所傳遞的參數;注意:路由中的state跟組件中的state是不同的;state參數只是路由中的一個屬性,跟組件裏面的state的沒有關係
<Link to={{pathname='/home/message/detail', state:{id:msgObj.id,title:msgObj.title}}}></Link>
複製代碼
用state傳遞參數的話刷新也能夠保留參數。此時雖然參數沒有在地址欄,可是也不會丟失,由於在這裏用BrowserRouter
來管理路由的,它一直在維護瀏覽器的history
,history
把傳遞的東西記下了,所以不會丟失。
home/a/b
時,在找home的路由的時候,會先匹配前面的home,匹配到了就找到了。這就是模糊匹配,且默認就是默認匹配。exact={true}
或exact
來開啓嚴格匹配通常狀況下咱們不開啓嚴格匹配,由於有時候開啓嚴格匹配會致使沒法繼續匹配二級路由
// 編寫路由連接 輸入的路徑
<Link to="/home/a/b">Home</Link>
// 註冊路由 匹配的路徑
<Route exact={true} path="/home" component={Home}></Route>
複製代碼
Switch
組件和Redirect
組件提升效率:Switch
組件。以下代碼,經過/home
匹配到Home組件以後就不會繼續匹配下去了。不然test組件也會被展現在頁面中。注意:要從react-router-dom
中引入Switch
。 Redirect
是react-router-dom
裏面的一個內置組件,會讓剛刷新瀏覽器的時候,默認跳轉到指定組件。(通常寫在全部路由註冊的最下方,當全部路由都沒法匹配時,跳轉到Redirect
指定的路由)
<Switch>
<Route path="/about" component={About}></Route>
<Route path="/home" component={Home}></Route>
<Route path="/home" component={test}></Route>
<Redirect to="/home"/>
</Switch>
複製代碼
通常狀況下咱們不會讓同一個路徑去對應展現多個組件,若是出現這種狀況的話就可使用Switch
。一般狀況下,path和component是一一對應的關係,Switch能夠提升路由匹配效率(單一匹配)。
加油!