# 6. vue-router原理总结
“更新视图但不重新请求页面”是前端路由原理的核心之一,目前在浏览器环境中这一功能的实现主要有两种方式:
- hash模式:利用URL中的hash(“#”)
- history模式:利用History interface在 HTML5中新增的方法
非浏览器环境下:
- abstract模式:利用数组栈的思想实现
window.addEventListener("hashchange", funcRef, false)
# hash 模式
# URL的井号
http://www.example.com/index.html#print
就代表网页index.html的print位置。浏览器读取这个URL后,会自动将print位置滚动至可视区域。- #是用来指导浏览器动作的,对服务器端完全无用。所以,HTTP请求中不包括#。第一个#后面出现的任何字符不会发送到服务器端。
- 单单改变#后的部分,浏览器只会滚动到相应位置,不会重新加载网页。
- 改变#会改变浏览器的访问历史
- window.location.hash读取#值
- onhashchange事件监听hash改变
# 思路
hash模式在浏览器支持/不支持window.history.pushState
、浏览器环境下使用。vue-router默认使用hash模式。
如果支持pushState
,则使用pushState
改变hash
,不支持使用window.location.hash = path
function pushHash (path) {
if (supportsPushState) {
pushState(getUrl(path))
} else {
window.location.hash = path
}
}
2
3
4
5
6
7
http://www.xxx.com/#/login
2
这种 #。后面 hash 值的变化,并不会导致浏览器向服务器发出请求,浏览器不发出请求,也就不会刷新页面。另外每次 hash 值的变化,还会触发hashchange 这个事件,通过这个事件我们就可以知道 hash 值发生了哪些变化。然后我们便可以监听hashchange来实现更新页面部分内容的操作:
function matchAndUpdate () {
// todo 匹配 hash 做 dom 更新操作
}
window.addEventListener('hashchange', matchAndUpdate)
2
3
4
5
# history 模式
这种模式在支持pushState、浏览器环境下使用。
因为 HTML5 标准发布。多了两个 API,pushState 和 replaceState,通过这两个 API 可以改变 url 地址且不会发送请求。同时还有popstate 事件。通过这些就能用另一种方式来实现前端路由了,但原理都是跟 hash 实现相同的。用了 HTML5 的实现,单页路由的 url 就不会多出一个#,变得更加美观。但因为没有 # 号,所以当用户刷新页面之类的操作时,浏览器还是会给服务器发送请求。为了避免出现这种情况,所以这个实现需要服务器的支持,需要把所有路由都重定向到根页面。
function matchAndUpdate () {
// todo 匹配路径 做 dom 更新操作
}
window.addEventListener('popstate', matchAndUpdate)
2
3
4
5
# abstract 模式
在非浏览器环境如node下使用。
因为它不是浏览器环境,所以它没有window.history,它不需要再去考虑popstate hashchange事件,不需要去管浏览器的地址栏,但是它需要自己管理路由历史记录。所在设置了stack数组来存储访问的路由对象,设置了一个index实例属性,来表示当前访问的路由位置。然后通过操作stack来实现push、replace、go功能。
# 总结
从设置路由改变到视图更新的流程如下:
$router.push() --> HashHistory.push() --> History.transitionTo() --> History.updateRoute() --> {app._route = route} --> vm.render()