1. 路由
- 傳統的路由指的是:當使用者通路一個
時,對應的伺服器會接收這個請求,然後解析url中的路徑,進而執行對應的處理邏輯。這樣就完成了一次路由分發。url
- 而前端路由是不涉及伺服器的,是前端利用
或者hash
的HTML5
來實作的,一般用于不同内容的展示和切換。history API
目前
Vue
推薦單頁面應用
SPA
開發模式,大型單頁應用最顯著特點之一就是采用前端路由系統,通過改變
URL
,在不重新請求頁面的情況下,更新頁面視圖。
Vue
中的路由解決方案為
vue-router
。
它提供兩種不同方式的路由方式:
Hash
和
History
,在
vue-router
中是使用了外觀模式将幾種不同的路由方式提供了一個一緻的高層接口,讓我們可以更解耦的在不同路由方式中切換。
Hash
和
History
除了外觀上的不同之外,還有一個差別是:
Hash
方式的狀态儲存需要另行傳遞,而
HTML5 History
原生提供了自定義狀态傳遞的能力,我們可以直接利用其來傳遞資訊。
在
vue-router
中是通過
mode
這一參數控制路由的實作模式的:

2. Hash
Hash
方法是在路由中帶有一個
#
,主要原理是通過監聽
#
後的
URL
路徑辨別符的更改而觸發的浏覽器
hashchange
事件,然後通過擷取
location.hash
得到目前的路徑辨別符,再進行一些路由跳轉的操作,參見 MDN:
-
:傳回完整的location.href
;URL
-
:傳回location.hash
的錨部分;URL
-
:傳回location.pathname
路徑名;URL
-
事件:當hashchange
發生改變時,将觸發這個事件。location.hash
比如通路一個路徑
http://sherlocked93.club/base/#/page1
,那麼上面幾個值分别為:
# http://sherlocked93.club/base/#/page1
{
"href": "http://sherlocked93.club/base/#/page1",
"pathname": "/base/",
"hash": "#/page1"
}
看一個例子:
<html>
<head>
<style>
li {
cursor: pointer;
}
</style>
</head>
<body>
<div id="main">
<p>router-hash</p>
<ul id="list">
<li><a href="#router1" target="_blank" rel="external nofollow" >router1</a></li>
<li><a href="#router2" target="_blank" rel="external nofollow" >router2</a></li>
<li><a href="#router3" target="_blank" rel="external nofollow" >router3</a></li>
</ul>
<div id="panel"></div>
</div>
<script>
window.onload = function () {
window.onhashchange = function (opt) {
console.log('hash has changed to: ', location.hash)
}
}
</script>
</body>
</html>
效果:
當我們點選後退時,可見路由跳轉回
router2
中。并且當我們重新整理頁面時不會報出
404
的錯誤,那是因為
hash
雖然出現在
URL
中,但不會被包括在
HTTP
請求中。它是用來指導浏覽器動作的,對伺服器端完全無用。
3. History API
HTML5
的
History API
為浏覽器的全局
history
對象增加的擴充方法。一般用來解決
ajax
請求無法通過回退按鈕回到請求前狀态的問題。
在
HTML4
原有的和
HTML5
新提出的
history
的API有:
-
; //在曆史記錄中前進一步history.forward()
-
; //在曆史記錄中後退一步history.back()
-
: //在曆史記錄中跳轉n步驟,n=0為重新整理本頁,n=-1為後退一頁。history.go(n)
-
//向曆史記錄中追加一條記錄history.pushState(data, title, url);
-
//替換目前頁在曆史記錄中的資訊history.replaceState(data, title, url);
-
//是一個屬性,可以得到目前頁的history.state;
資訊。state
-
//是一個事件,在點選浏覽器後退按鈕或window.onpopstate;
調用js
、forward()
、back()
時觸發。監聽函數中可傳入一個go()
對象,event
即為通過event.state
或pushState()
方法傳入的replaceState()
參數。data
以一個例子實作一下:
<html>
<head>
<style>
li {
cursor: pointer;
}
</style>
</head>
<body>
<div id="main">
<p>vue-router</p>
<ul id="list">
<li>router1</li>
<li>router2</li>
<li>router3</li>
</ul>
<div id="panel"></div>
</div>
<script>
window.onload = function () {
window.onpopstate = function (event) {
console.log(event)
};
document.querySelector('#list').addEventListener('click', function (event) {
if(event.target.nodeName.toLowerCase()==="li") {
var content = event.target.innerHTML;
var _newState;
_newState = {
url: location.origin + '/' + content,
title: document.title,
state: content
};
window.history.pushState(_newState, '', '/' + content);
console.log('you have change the router to: ', content);
}
})
}
</script>
</body>
</html>
效果:
總而言之就是當浏覽器通路一個頁面時,目前位址的狀态資訊會被壓入曆史棧,當調用
history.pushState()
方法向曆史棧中壓入一個新的
state
後,曆史棧頂部的指針是指向新的
state
的。可以将其作用簡單了解為假裝已經修改了
url
位址并進行了跳轉 ,除非使用者點選了浏覽器的前進、回退,或是顯式調用
HTML4
中的操作曆史棧的方法,否則不會觸發全局的
popstate
事件。以上例子中點選後退可見由目前的
router2
跳轉到
router3
,控制台列印出
popstate
事件資訊。
當我們重新整理頁面的時候,會報出
404
的錯誤:
這也是
history
不同于
hash
的一個地方,是因為
history
模式則會将
URL
修改得就和正常向後端發起請求一樣,如果後端沒有配置對應的路由處理,則會傳回
404
錯誤。
官方推薦的解決辦法是在服務端增加一個覆寫所有情況的候選資源:如果
URL
比對不到任何靜态資源,則應該傳回同一個
index.html
頁面,這個頁面就是你
app
依賴的頁面。
參考:
https://www.cnblogs.com/dashnowords/p/9671213.html 大史不說話
https://juejin.im/post/5c52da9ee51d45221f242804 SHERlocked93