前端工程采用 SPA 模式 hashHistory , 在集成到生產(chǎn)環(huán)境中的時(shí)候,使用browserHistory :
var his;
if (isDev) {
//SPA
his = hashHistory
} else {
his = browserHistory
}
let routes =
<Route path="/">
<IndexRedirect to="index"/>
<Route path="index" component={PageHome}/>
<Route path="article_list" component={PageArticleList}/>
<Route path="category_list" component={PageCategoryList}/>
<Route path="tag_list" component={PageTagList}/>
</Route>
let router = <Router routes={routes} history={his}/>
ReactDOM.render(router, document.getElementById('App'))
Histories
需要依賴: ReactRouter.min.js
Histories
React Router 是建立在 history 之上的。
簡(jiǎn)而言之,一個(gè) history 知道如何去監(jiān)聽(tīng)瀏覽器地址欄的變化,
并解析這個(gè) URL 轉(zhuǎn)化為 location 對(duì)象,
然后 router 使用它匹配到路由,最后正確地渲染對(duì)應(yīng)的組件。
常用的 history 有三種形式,
但是你也可以使用 React Router 實(shí)現(xiàn)自定義的 history。
你可以從 React Router 中引入它們:
// JavaScript 模塊導(dǎo)入(譯者注:ES6 形式)
import { browserHistory } from 'react-router'
然后將它們傳遞給<Router>:
render(
<Router history={browserHistory} routes={routes} />,
document.getElementById('app')
)
browserHistory
Browser history 是使用 React Router 的應(yīng)用推薦的 history。它使用瀏覽器中的 History API 用于處理 URL,創(chuàng)建一個(gè)像example.com/some/path這樣真實(shí)的 URL 。
服務(wù)器配置
服務(wù)器需要做好處理 URL 的準(zhǔn)備。處理應(yīng)用啟動(dòng)最初的 / 這樣的請(qǐng)求應(yīng)該沒(méi)問(wèn)題,但當(dāng)用戶來(lái)回跳轉(zhuǎn)并在 /accounts/123 刷新時(shí),服務(wù)器就會(huì)收到來(lái)自 /accounts/123 的請(qǐng)求,這時(shí)你需要處理這個(gè) URL 并在響應(yīng)中包含 JavaScript 應(yīng)用代碼。
一個(gè) express 的應(yīng)用可能看起來(lái)像這樣的:
const express = require('express')
const path = require('path')
const port = process.env.PORT || 8080
const app = express()
// 通常用于加載靜態(tài)資源
app.use(express.static(__dirname + '/public'))
// 在你應(yīng)用 JavaScript 文件中包含了一個(gè) script 標(biāo)簽
// 的 index.html 中處理任何一個(gè) route
app.get('*', function (request, response){
response.sendFile(path.resolve(__dirname, 'public', 'index.html'))
})
app.listen(port)
console.log("server started on port " + port)
如果你的服務(wù)器是 nginx,請(qǐng)使用 try_files 指令:
server {
...
location / {
try_files $uri /index.html
}
}
當(dāng)在服務(wù)器上找不到其他文件時(shí),這可以讓 nginx 服務(wù)器提供靜態(tài)文件服務(wù)并指向index.html 文件。
對(duì)于Apache服務(wù)器也有類似的方式,創(chuàng)建一個(gè).htaccess文件在你的文件根目錄下:
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
IE8, IE9 支持情況
如果我們能使用瀏覽器自帶的 window.history API,那么我們的特性就可以被瀏覽器所檢測(cè)到。如果不能,那么任何調(diào)用跳轉(zhuǎn)的應(yīng)用就會(huì)導(dǎo)致 全頁(yè)面刷新,它允許在構(gòu)建應(yīng)用和更新瀏覽器時(shí)會(huì)有一個(gè)更好的用戶體驗(yàn),但仍然支持的是舊版的。
你可能會(huì)想為什么我們不后退到 hash history,問(wèn)題是這些 URL 是不確定的。如果一個(gè)訪客在 hash history 和 browser history 上共享一個(gè) URL,然后他們也共享同一個(gè)后退功能,最后我們會(huì)以產(chǎn)生笛卡爾積數(shù)量級(jí)的、無(wú)限多的 URL 而崩潰。
hashHistory
Hash history 使用 URL 中的 hash(#)部分去創(chuàng)建形如 example.com/#/some/path 的路由。
我應(yīng)該使用 createHashHistory嗎?
Hash history 不需要服務(wù)器任何配置就可以運(yùn)行,如果你剛剛?cè)腴T,那就使用它吧。但是我們不推薦在實(shí)際線上環(huán)境中用到它,因?yàn)槊恳粋€(gè) web 應(yīng)用都應(yīng)該渴望使用 browserHistory。
像這樣 ?_k=ckuvup 沒(méi)用的在 URL 中是什么?
當(dāng)一個(gè) history 通過(guò)應(yīng)用程序的 push 或 replace 跳轉(zhuǎn)時(shí),它可以在新的 location 中存儲(chǔ) “l(fā)ocation state” 而不顯示在 URL 中,這就像是在一個(gè) HTML 中 post 的表單數(shù)據(jù)。
在 DOM API 中,這些 hash history 通過(guò) window.location.hash = newHash 很簡(jiǎn)單地被用于跳轉(zhuǎn),且不用存儲(chǔ)它們的location state。但我們想全部的 history 都能夠使用location state,因此我們要為每一個(gè) location 創(chuàng)建一個(gè)唯一的 key,并把它們的狀態(tài)存儲(chǔ)在 session storage 中。當(dāng)訪客點(diǎn)擊“后退”和“前進(jìn)”時(shí),我們就會(huì)有一個(gè)機(jī)制去恢復(fù)這些 location state。
createMemoryHistory
Memory history 不會(huì)在地址欄被操作或讀取。這就解釋了我們是如何實(shí)現(xiàn)服務(wù)器渲染的。同時(shí)它也非常適合測(cè)試和其他的渲染環(huán)境(像 React Native )。
和另外兩種history的一點(diǎn)不同是你必須創(chuàng)建它,這種方式便于測(cè)試。
const history = createMemoryHistory(location)
實(shí)現(xiàn)示例
import React from 'react'
import { render } from 'react-dom'
import { browserHistory, Router, Route, IndexRoute } from 'react-router'
import App from '../components/App'
import Home from '../components/Home'
import About from '../components/About'
import Features from '../components/Features'
render(
<Router history={browserHistory}>
<Route path='/' component={App}>
<IndexRoute component={Home} />
<Route path='about' component={About} />
<Route path='features' component={Features} />
</Route>
</Router>,
document.getElementById('app')
)