在單頁應用中,一般由前端來配置路由,根據不一樣的 url 顯示不一樣的內容。想要知道這是如何作到的,首先得了解瀏覽器提供的兩大 API:前端
window.location
vue
location.href
location.hash
location.search
location.pathname
window.history
vue-router
history.pushState()
history.replaceState()
history.go()
history.back()
history.forward()
咱們先了解 location 對象,location 有不少的屬性。咱們能夠經過改變其屬性值修改頁面的 url。咱們在單頁應用中須要作到的是改變 url 不刷新頁面,location 接口提供如下兩種方式能夠作到:後端
location.href
賦值時只改變 url 的 hashlocation.hash
而上面的列出其他兩個屬性 location.search
會直接刷新頁面,這個就不解釋了。但 location.pathname
照道理來講只改變 hash 應該是能夠的,但實際上瀏覽器會編碼這個屬性值,因此沒法直接賦帶 # 號的值。瀏覽器
history 接口是 HTML5 新增的,它有五個方法能夠改變 url 而不刷新頁面。編碼
history.pushState()
history.replaceState()
history.go()
上面只演示了三個方法,由於 history.back()
等價於 history.go(-1)
,history.forward()
則等價於 history.go(1)
,這三個接口等同於瀏覽器界面的前進後退。url
如今咱們已經知道如何不刷新頁面改變頁面的 url。雖然頁面沒刷新,但咱們要改變頁面顯示的內容。這就須要 js 監聽 url 的變化從而達到咱們的目的。spa
咱們有兩個事件能夠監聽 url 的改變:code
hashchange
事件能監聽 url hash 的改變。router
先要加上事件監聽的代碼:
window.addEventListener('hashchange', function(e) { console.log(e) })
而後就能夠在頁面的 console 裏愉快的實驗了:
從上圖中咱們能夠知道無論是經過 location 接口直接改變 hash,仍是經過 history 接口前進後退(只是 hash 改變的狀況下),咱們均可以監聽到 url hash 的改變。但這個事件也只能監聽 url hash 的變化。因此咱們須要一個更強大的事件:popstate
。
popstate 事件能監聽除 history.pushState()
和 history.replaceState()
外 url 的變化。
先加上事件監聽的代碼:
window.addEventListener('popstate', function(e) { console.log(e) })
而後又能夠在頁面的 console 裏愉快的實驗了:
其實不止 history.pushState()
和 history.replaceState()
對 url 的改變不會觸發 popstate
事件,當這兩個方法只改變 url hash 時也不會觸發 hashchange
事件。
咱們都知道單頁應用的路由有兩種模式:hash 和 history。若是咱們在 hash 模式時不使用 history.pushState()
和 history.replaceState()
方法,咱們就只須要在 hashchange
事件回調裏編寫 url 改變時的邏輯就好了。而 history 模式下,咱們不只要在 popstate
事件回調裏處理 url 的變化,還須要分別在 history.pushState()
和 history.replaceState()
方法裏處理 url 的變化。並且 history 模式還須要後端的配合,否則用戶刷新頁面就只有 404 能夠看了?
因此 hash 模式下咱們的工做實際上是更簡單的,但爲何如今都推薦用 history 模式呢?總不是 hash 模式下的 url 太醜了,畢竟這是個看臉的世界?
不過 vue-router
在瀏覽器支持 pushState()
時就算是 hash 模式下也是用 history.pushState()
來改變 url,不知道有沒什麼深意?還有待研究...