起源
什么是路由?路由其实就是指向一个特定处理函数的路径(后端:一个路由对应一个controller)
前端Ajax => 局部刷新 => SPA
| 多页应用 | 单页应用 |
|---|---|
| 一个项目中有多个完整的的HTML文件 | 一个项目中只有一个完整的HTML页面(index.html) |
| 可以使用超链接、js实现页面间的跳转 | 可以使用改进后的超链接、js实现模板页面间的切换 |
| 传统的页面跳转是同步请求:在服务器生成响应内容时,客户端是一片空白 | 模板页面间的切换属于经典的异步请求:直到下一个模板页面来到,前一个模板页面到来,前一个模板页面才从当前DOM树上删除 |
| 页面跳转时,前一个DOM树无用了,需要从浏览器中全部删除,然后等待下一个DOM树的到来 | index.html到来时,浏览器创建一个DOM树。所有的请求都是xhr,到来时只需要作为一个片段挂载在当前DOM树——浏览器从始至终只有一个DOM树 |
| 当网速比较慢时(尤其是移动端应用中时),用户体验极为不好! | 不会出现一片惨白的情形,浏览体验好。 |
| 页面切换时,DOM被完整的删除,不可能有过场动画! | 页面切换的本质是DIV的轮换,可以很容易实现漂亮的过场动画。 |
SPA存在的问题: 所有的页面共享一个URL,无法区分,对爬虫、SEO等不友好
=> 前端路由出现:页面切换时改变URL,同时不请求后端刷新html页面
两种路由模式
hash
- hash值的改变不会引起页面刷新
- window.onhashchange可以监听到路由的变化
- 将hash值与页面切换处理函数一一对应
history
- HTML5引入了history.pushState() 和 history.replaceState() 方法,分别可以添加和修改历史记录条目,将使浏览器地址栏显示为新地址,但并不会导致浏览器加载页面,甚至不会检查新地址是否存在。使用 history.pushState() 可以改变referrer,它在用户发送 XMLHttpRequest 请求时在HTTP头部使用,改变state后创建的 XMLHttpRequest 对象的referrer都会被改变。因为referrer是标识创建 XMLHttpRequest 对象时 this 所代表的window对象中document的URL。History_API。pushState() 绝对不会触发 hashchange 事件,即使新的URL与旧的URL仅哈希不同也是如此。
- 调用history.pushState()或者history.replaceState()不会触发popstate事件. popstate事件只会在浏览器某些行为下触发, 比如点击后退、前进按钮(或者在JavaScript中调用history.back()、history.forward()、history.go()方法)。onpopstate
- pushState之后,在popstate触发时绑定页面切换处理函数
Vue-router的路由实现
项目地址:https://github.com/vuejs/vue-router
HTML5History源码实现(/src/index.js)
push (location: RawLocation, onComplete?: Function, onAbort?: Function) {
// $flow-disable-line
if (!onComplete && !onAbort && typeof Promise !== 'undefined') {
return new Promise((resolve, reject) => {
this.history.push(location, resolve, reject)
})
} else {
this.history.push(location, onComplete, onAbort)
}
}
replace (location: RawLocation, onComplete?: Function, onAbort?: Function) {
// $flow-disable-line
if (!onComplete && !onAbort && typeof Promise !== 'undefined') {
return new Promise((resolve, reject) => {
this.history.replace(location, resolve, reject)
})
} else {
this.history.replace(location, onComplete, onAbort)
}
}
go (n: number) {
this.history.go(n)
}
back () {
this.go(-1)
}
forward () {
this.go(1)
}
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)
}
replace (location: RawLocation, onComplete?: Function, onAbort?: Function) {
const { current: fromRoute } = this
this.transitionTo(location, route => {
replaceState(cleanPath(this.base + route.fullPath))
handleScroll(this.router, route, fromRoute, false)
onComplete && onComplete(route)
}, onAbort)
}
export function pushState (url?: string, replace?: boolean) {
saveScrollPosition()
// try...catch the pushState call to get around Safari
// DOM Exception 18 where it limits to 100 pushState calls
const history = window.history
try {
if (replace) {
history.replaceState({ key: _key }, '', url)
} else {
_key = genKey()
history.pushState({ key: _key }, '', url)
}
} catch (e) {
window.location[replace ? 'replace' : 'assign'](url)
}
}
export function replaceState (url?: string) {
pushState(url, true)
}
router 实例调用的 push 实际是 history 的方法,通过 mode 来确定匹配 history
的实现方案,从代码中我们看到,push 调用了 src/util/push-state.js 中被改写过
的 pushState 的方法,改写过的方法会根据传入的参数 replace?: boolean 来进行
判断调用 pushState 还是 replaceState ,同时做了错误捕获,如果,history 无刷
新修改访问路径失败,则调用 window.location.replace(url) ,有刷新的切换用户访
问地址 ,同理 pushState 也是这样。这里的 transitionTo 方法主要的作用是做视图
的跟新及路由跳转监测,如果 url 没有变化(访问地址切换失败的情况),在
transitionTo 方法内部还会调用一个 ensureURL 方法,来修改 url。
本文介绍了前端路由的起源,详细讲解了Vue-router的两种路由模式:hash模式和history模式。hash模式利用hash值变化不刷新页面的特性实现路由;而history模式借助HTML5的History API实现页面路由的平滑切换。Vue-router通过mode属性选择不同的实现方式,结合pushState或replaceState处理页面更新。
1033

被折叠的 条评论
为什么被折叠?



