衆所周知,vue-router
有三種模式 :hash
、html5
、abstract
, 通常的前端項目中會選擇hash
模式進行開發,最近作了一個運營活動就是基於vue-router的hash模式
進行開發的。html
var router = new VueRouter({ routes: [{ name: 'index', path: '', component: indexcomponent },{ name: 'demo', path: '/demo', component: democomponent }] });
https://www.xxx.com?from=weixin
, 瀏覽器裏輸入URL回車後,頁面自動增長一個#/
變爲https://www.xxx.com?from=weixin#/
。https://www.xxx.com?from=weixin#/test?userId=123
router.push({ path: 'demo', query: { plan: 'private' } })
統一資源定位符(或稱統一資源定位器/定位地址、URL地址等,英語:Uniform Resource Locator,常縮寫爲URL)
標準格式:scheme:[//authority]path[?query][#fragment]
前端
==例子==vue
下圖展現了兩個 URI 例子及它們的組成部分。<!-- 基於 RFC 3986 中的例子格式 -->
<pre style="font-family:Courier,Courier New,DejaVu Sans Mono;monospace">html5
hierarchical part ┌───────────────────┴─────────────────────┐ authority path ┌───────────────┴───────────────┐┌───┴────┐
abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
└┬┘ └───────┬───────┘ └────┬────┘ └┬┘ └─────────┬─────────┘ └──┬──┘
scheme user information host port query fragmentgit
urn:example:mammal:monotreme:echidna
└┬┘ └──────────────┬───────────────┘
scheme path</pre>github
『?』vue-router
『#』segmentfault
Request Headers
中的Referer
不包含#http://www.xxx.com/?color=#fff
發出請求是:/color=
)window.location.hash
讀取#值URL讀取和操做涉及location和history兩個對象,具體以下:設計模式
location API :api
屬性
方法
history API:
方法
H5新增API
初始化router的時候,根據指定的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}`) } }
咱們選擇hash
模式進行深刻分析,對應HashHistory
模塊,該模塊是history/hash.js
實現的,當被調用的時候,對全局路由變化進行了監聽
window.addEventListener(supportsPushState ? 'popstate' : 'hashchange', () => { ... })
同時hash.js
中也實現了push
等api方法的封裝,咱們以push
爲例,根據源碼能夠看出,它的實現是基於基類transitionTo
的實現,具體以下:
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) }
既然調用了transitionTo
那麼來看它的實現,獲取參數後調用confirmTransition
transitionTo (location: RawLocation, onComplete?: Function, onAbort?: Function) { // 獲取URL中的參數 const route = this.router.match(location, this.current) this.confirmTransition(route, () => { this.updateRoute(route) onComplete && onComplete(route) this.ensureURL() ... }) }
同時confirmTransition
裏實現了一個隊列,順序執行,iterator
經過後執行next
,進而志新pushHash()
,實現頁面hash改變,最終實現了${base}#${path}
的鏈接
function getUrl (path) { const href = window.location.href const i = href.indexOf('#') const base = i >= 0 ? href.slice(0, i) : href return `${base}#${path}` } function pushHash (path) { if (supportsPushState) { pushState(getUrl(path)) } else { window.location.hash = path } }
https://www.xxx.com?from=weixin#/test?userId=123
這個頁面看起來感受怪,是由於這個鏈接中幾乎包含了全部的參數,並且hash裏面還有一個問號,一個URL中多個問號的不常見