VUE路由的工作原理
1.vue路由的两种模式hash模式:比如 'http://www.baidu.com/#/abc'hash 的值为 '#/abc'它的特点在于:hash 虽然出现 URL 中,但不会被包含在 HTTP 请求中,因此改变 hash 不会重新加载页面但是会触发 onhashchange 事件,所以我们可以监听,然后渲染自己要渲染的组件,达到路由的效果history模式:通过 HTML5 中新增的 p
1.vue路由的两种模式
hash模式:
比如 'http://www.baidu.com/#/abc' hash 的值为 '#/abc'
它的特点在于:hash 虽然出现 URL 中,但不会被包含在 HTTP 请求中,因此改变 hash 不会重新加载页面
但是会触发 onhashchange 事件,所以我们可以监听,然后渲染自己要渲染的组件,达到路由的效果
history模式:
通过 HTML5 中新增的 pushState() replaceState() 方法
应用于浏览器的历史记录,在已有的 go(),back(),forward() 的基础之上,它们提供了对历史记录进行修改的功能
当它们执行修改时,虽然改变了当前的 URL,但你浏览器不会立即向后端发送请求
我们可以通过 onpopstate 事件,监听 history 的变化,然后渲染自己要渲染的组件,达到路由的效果
2、hash的特点
hash变化会触发网页跳转,即浏览器的前进和后退。
hash 可以改变 url ,但是不会触发页面重新加载(hash的改变是记录在 window.history 中),即不会刷新页面。也就是说,所有页面的跳转都是在客户端进行操作。因此,这并不算是一次 http 请求,所以这种模式不利于 SEO 优化。hash 只能修改 # 后面的部分,所以只能跳转到与当前 url 同文档的 url 。
hash 通过 window.onhashchange 的方式,来监听 hash 的改变,借此实现无刷新跳转的功能。
hash 永远不会提交到 server 端(可以理解为只在前端自生自灭)。
更新视图但不重新请求页面,是前端路由原理的核心之一,目前在浏览器环境中这一功能的实现主要有2
种方式:
- 利用
URL
中的hash
("#"
); - 利用
History interface
在HTML5
中新增的方法;
vue-router
是Vue.js
框架的路由插件,它是通过mode
这一参数控制路由的实现模式的:
const router=new VueRouter({
mode:'history',
routes:[...]
})
创建VueRouter
的实例对象时,mode
以构造参数的形式传入。
src/index.js
export default class VueRouter{
mode: string; // 传入的字符串参数,指示history类别
history: HashHistory | HTML5History | AbstractHistory; // 实际起作用的对象属性,必须是以上三个类的枚举
fallback: boolean; // 如浏览器不支持,'history'模式需回滚为'hash'模式
constructor (options: RouterOptions = {}) {
let mode = options.mode || 'hash' // 默认为'hash'模式
this.fallback = mode === 'history' && !supportsPushState // 通过supportsPushState判断浏览器是否支持'history'模式
if (this.fallback) {
mode = 'hash'
}
if (!inBrowser) {
mode = 'abstract' // 不在浏览器环境下运行需强制为'abstract'模式
}
this.mode = mode
// 根据mode确定history实际的类并实例化
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}`)
}
}
}
init (app: any /* Vue component instance */) {
const history = this.history
// 根据history的类别执行相应的初始化操作和监听
if (history instanceof HTML5History) {
history.transitionTo(history.getCurrentLocation())
} else if (history instanceof HashHistory) {
const setupHashListener = () => {
history.setupListeners()
}
history.transitionTo(
history.getCurrentLocation(),
setupHashListener,
setupHashListener
)
}
history.listen(route => {
this.apps.forEach((app) => {
app._route = route
})
})
}
// VueRouter类暴露的以下方法实际是调用具体history对象的方法
push (location: RawLocation, onComplete?: Function, onAbort?: Function) {
this.history.push(location, onComplete, onAbort)
}
replace (location: RawLocation, onComplete?: Function, onAbort?: Function) {
this.history.replace(location, onComplete, onAbort)
}
}
- 作为参数传入的字符串属性
mode
只是一个标记,用来指示实际起作用的对象属性history
的实现类,两者对应关系:
modehistory:
'history':HTML5History;
'hash':HashHistory;
'abstract':AbstractHistory;
- 在初始化对应的
history
之前,会对mode
做一些校验:若浏览器不支持HTML5History
方式(通过supportsPushState
变量判断),则mode
设为hash
;若不是在浏览器环境下运行,则mode
设为abstract
; VueRouter
类中的onReady()
,push()
等方法只是一个代理,实际是调用的具体history
对象的对应方法,在init()
方法中初始化时,也是根据history
对象具体的类别执行不同操作
两种模式比较
一般的需求场景中,hash
模式与history
模式是差不多的,根据MDN
的介绍,调用history.pushState()
相比于直接修改hash
主要有以下优势:
pushState
设置的新url
可以是与当前url
同源的任意url
,而hash
只可修改#
后面的部分,故只可设置与当前同文档的url
pushState
设置的新url
可以与当前url
一模一样,这样也会把记录添加到栈中,而hash
设置的新值必须与原来不一样才会触发记录添加到栈中pushState
通过stateObject
可以添加任意类型的数据记录中,而hash
只可添加短字符串pushState
可额外设置title
属性供后续使用
history
模式的问题
对于单页应用来说,理想的使用场景是仅在进入应用时加载index.html
,后续在的网络操作通过ajax
完成,不会根据url
重新请求页面,但是如果用户直接在地址栏中输入并回车,浏览器重启重新加载等特殊情况。
hash
模式仅改变hash
部分的内容,而hash
部分是不会包含在http
请求中的(hash
带#
):
http://oursite.com/#/user/id //如请求,只会发送http://oursite.com/
所以hash
模式下遇到根据url
请求页面不会有问题
而history
模式则将url
修改的就和正常请求后端的url
一样(history
不带#
)
http://oursite.com/user/id
如果这种向后端发送请求的话,后端没有配置对应/user/id
的get
路由处理,会返回404
错误。
更多推荐
所有评论(0)