vue-router
默認是 hash
模式 , 即便用 URL
的 hash
來模擬一個完整的 URL
,因而當 URL
改變時,頁面不會從新加載。javascript
vue-router
還支持 history
模式,這種模式充分利用了 history.pushState
來完成 URL
跳轉。html
在不支持 history.pushState
的瀏覽器 , 會自動會退到 hash
模式。vue
是否回退能夠經過
fallback
配置項來控制,默認值爲 true
const router = new VueRouter({ mode: 'history', // history 或 hash routes: [...] });
詳細使用可參看文檔: HTML5 History 模式html5
首先看下 VueRouter 的構造方法 , 文件位置 src/index.js
java
import { HashHistory } from './history/hash' import { HTML5History } from './history/html5' import { AbstractHistory } from './history/abstract' // ... more constructor(options: RouterOptions = {}) { // ... more // 默認hash模式 let mode = options.mode || 'hash' // 是否降級處理 this.fallback = mode === 'history' && !supportsPushState && options.fallback !== false // 進行降級處理 if (this.fallback) { mode = 'hash' } if (!inBrowser) { mode = 'abstract' } this.mode = mode // 根據不一樣的mode進行不一樣的處理 switch (mode) { case 'history': this.history = new HTML5History(this, options.base) break case 'hash': this.history = new HashHistory(this, options.base, this.fallback) break case 'abstract': this.history = new AbstractHistory(this, options.base) break default: if (process.env.NODE_ENV !== 'production') { assert(false, `invalid mode: ${mode}`) } } }
咱們能夠看到,會判斷是否支持 history
, 而後根據 fallback
來肯定是否要降級。而後,根據不一樣的 mode
, 分別實例化不一樣的 history
。 (HTML5History、HashHistory、AbstractHistory
)vue-router
咱們看到 , HTML5History、HashHistory、AbstractHistory
都是來自 history 目錄。segmentfault
├── history // 操做瀏覽器記錄的一系列內容 │ ├── abstract.js // 非瀏覽器的history │ ├── base.js // 基本的history │ ├── hash.js // hash模式的history │ └── html5.js // html5模式的history
其中, base.js 裏面定義了 History 類瀏覽器
基本的關係以下圖:
ide
base.js
裏面定義了一些列的方法, hash
、html5
模式,分別繼承了這些方法,並實現了本身特有的邏輯ui
從外部調用的時候,會直接調用到 this.history
, 而後,因爲初始化對象的不一樣,而進行不一樣的操做。
接下來, 咱們挑選其中一個咱們最經常使用到的 push
方法來解釋一整個過程
咱們平時調用的時候, 一直都是用 this.$router.push('home')
, 這種形式調用。
首先,在 VueRouter
對象上有一個 push 方法 。
// 文件位置: src/index.js export default class VueRouter { // ... more push(location: RawLocation, onComplete?: Function, onAbort?: Function) { this.history.push(location, onComplete, onAbort); } }
咱們看到,其沒有作任何處理,直接轉發到 this.history.push(location, onComplete, onAbort)
。
上面咱們講到,這個處理,會根據 history 的初始化對象不一樣而作不一樣處理。咱們來分別看看細節
export class HashHistory extends History { // ...more // 跳轉到 push(location: RawLocation, onComplete?: Function, onAbort?: Function) { const { current: fromRoute } = this; this.transitionTo( location, route => { pushHash(route.fullPath); handleScroll(this.router, route, fromRoute, false); onComplete && onComplete(route); }, onAbort ); } } // 切換路由 // 會判斷是否支持pushState ,支持則使用pushState,不然切換hash function pushHash(path) { if (supportsPushState) { pushState(getUrl(path)); } else { window.location.hash = path; } }
export class HTML5History extends History { // ...more // 增長 hash push(location: RawLocation, onComplete?: Function, onAbort?: Function) { const { current: fromRoute } = this; this.transitionTo( location, route => { pushState(cleanPath(this.base + route.fullPath)); handleScroll(this.router, route, fromRoute, false); onComplete && onComplete(route); }, onAbort ); } }
兩種模式的 push
實現區別並不大,都是調用了 transitionTo
, 區別在於: 一個調用 pushHash
, 一個調用 pushState
.
其餘的 go
、 replace
、getCurrentLocation
都是相似的實現方式。
transitionTo
的具體實現,這裏就先不詳聊了,後面聊到路由守護的時候,會細講這一塊內容。