一首有、概念闡述
對于 Vue 這類漸進式前端開發(fā)框架,為了構(gòu)建 SPA(單頁面應(yīng)用)箭券,需要引入前端路由系統(tǒng),這也就是 Vue-Router 存在的意義疑枯。前端路由的核心辩块,就在于 —— 改變視圖的同時不會向后端發(fā)出請求。
為了達到這一目的,瀏覽器當前提供了以下兩種支持:
-
hash —— 即地址欄 URL 中的
#
符號(此 hash 不是密碼學(xué)里的散列運算)庆捺。
比如這個 URL:[http://www.abc.com/#/hello](http://www.abc.com/#/hello)
古今,hash 的值為#/hello
。它的特點在于:hash 雖然出現(xiàn)在 URL 中滔以,
但不會被包括在 HTTP 請求中,對后端完全沒有影響氓拼,因此改變 hash 不會重新加載頁面你画。 -
history —— 利用了 HTML5 History Interface 中新增的
pushState()
和replaceState()
方法。(需要特定瀏覽器支持)這兩個方法應(yīng)用于瀏覽器的歷史記錄棧桃漾,在當前已有的back
坏匪、forward
、go
的基礎(chǔ)之上撬统,它們提供了對歷史記錄進行修改的功能适滓。只是當它們執(zhí)行修改時,雖然改變了當前的 URL恋追,但瀏覽器不會立即向后端發(fā)送請求凭迹。
因此,hash 模式和 history 模式都屬于瀏覽器自身的特性苦囱,Vue-Router 只是利用了這兩個特性(通過調(diào)用瀏覽器提供的接口)來實現(xiàn)前端路由嗅绸。
二、為什么變遷
一般場景下撕彤,hash 和 history 都可以實現(xiàn)路由跳轉(zhuǎn)鱼鸠,默認是hash模式。那么為什么要變遷呢羹铅?理由如下:
1蚀狰、顏值
“#”符號夾雜在 URL 里看起來確實有些不太美麗,所以要把#去掉职员。
2麻蹋、跨域問題
在項目開發(fā)過程中,路由跳轉(zhuǎn)帶#的url請求和普通接口url請求的混用廉邑,產(chǎn)生了令人頭疼的跨域問題哥蔚。需要將url中的“#”去掉。
3蛛蒙、其他
根據(jù) Mozilla Develop Network 的介紹糙箍,調(diào)用 history.pushState() 相比于直接修改 hash
,存在以下優(yōu)勢:
-
pushState()
設(shè)置的新 URL 可以是與當前 URL 同源的任意 URL牵祟;而hash
只可修改#
后面的部分深夯,因此只能設(shè)置與當前 URL 同文檔的 URL; -
pushState()
設(shè)置的新 URL 可以與當前 URL 一模一樣,這樣也會把記錄添加到棧中咕晋;而hash
設(shè)置的新值必須與原來不一樣才會觸發(fā)動作將記錄添加到棧中雹拄; -
pushState()
通過stateObject
參數(shù)可以添加任意類型的數(shù)據(jù)到記錄中;而hash
只可添加短字符串掌呜; -
pushState()
可額外設(shè)置title
屬性供后續(xù)使用滓玖。
當然,history
也不是樣樣都好质蕉。SPA 雖然在瀏覽器里游刃有余势篡,但真要通過 URL 向后端發(fā)起 HTTP 請求時,兩者的差異就來了模暗。尤其在用戶手動輸入 URL 后回車禁悠,或者刷新(重啟)瀏覽器的時候。
-
hash
模式下兑宇,僅hash
符號之前的內(nèi)容會被包含在請求中碍侦,如[http://www.abc.com](http://www.abc.com/)
,因此對于后端來說隶糕,即使沒有做到對路由的全覆蓋瓷产,也不會返回 404 錯誤。 -
history
模式下若厚,前端的 URL 必須和實際向后端發(fā)起請求的 URL 一致拦英,如[http://www.abc.com/book/id](http://www.abc.com/book/id)
。如果后端缺少對/book/id
的路由處理测秸,將返回 404 錯誤疤估。Vue-Router 官網(wǎng)里如此描述:“不過這種模式要玩好,還需要后臺配置支持……所以呢霎冯,你要在服務(wù)端增加一個覆蓋所有情況的候選資源:如果 URL 匹配不到任何靜態(tài)資源铃拇,則應(yīng)該返回同一個 index.html 頁面,這個頁面就是你 app 依賴的頁面沈撞】独螅”
三、如何變遷
1缠俺、前端修改
在創(chuàng)建VueRouter對象的地方添加mode:'history'屬性显晶。
const router = new VueRouter({
mode: 'history',
routes: [...]
})
注意,如果前端文件不是部署在服務(wù)器的根目錄下壹士,還要修改另外幾個地方磷雇。
假如部署在Project文件夾下,在new VueRouter對象的時候躏救,要添加一個base屬性唯笙,如下所示:
const router = new VueRouter({
mode: 'history',
base: '/Project/',
routes: [...]
})
另外螟蒸,在config-->index.js文件中,將assetsPublicPath屬性也改為/Project/崩掘,如下所示:
build: {
// Template for index.html
index: path.resolve(__dirname, '../dist/index.html'),
// Paths
assetsRoot: path.resolve(__dirname, '../dist'),
assetsSubDirectory: 'static',
assetsPublicPath: '/Project/',
}
2七嫌、后端配置
Apache
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</IfModule>
除了 mod_rewrite
,也可以使用 FallbackResource
苞慢。
nginx
location / {
try_files $uri $uri/ /index.html;
}
原生 Node.js
const http = require('http')
const fs = require('fs')
const httpPort = 80
http.createServer((req, res) => {
fs.readFile('index.htm', 'utf-8', (err, content) => {
if (err) {
console.log('We cannot open "index.htm" file.')
}
res.writeHead(200, {
'Content-Type': 'text/html; charset=utf-8'
})
res.end(content)
})
}).listen(httpPort, () => {
console.log('Server listening on: http://localhost:%s', httpPort)
})
四诵原、變遷后帶來的問題及解決辦法
變遷為history之后,url中不再帶“#”符號枉疼,美觀了皮假,也能解決跨域的問題了。但是引起了新的問題骂维。
1、vue頁面中的href贺纲、window.open()等使用相對路徑時航闺,指向的鏈接自動變的不對了。
解決辦法:
- 使用絕對路徑猴誊,但是使用絕對路徑比較麻煩潦刃,不推薦。
- 查看錯誤鏈接懈叹,和正確的鏈接對比乖杠,對了或者少了什么,然后進行修正澄成。
參考鏈接:
https://router.vuejs.org/zh/guide/essentials/history-mode.html
https://segmentfault.com/q/1010000010340823/a-1020000011352255