众所周知,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中多个问号的不常见