志在指尖
用双手敲打未来

vue-router(vue-router的实现原理)

vue-router

vue中的vue-router是通过hash和history两种形式完成前端跳转路由,更新视图但不重新恳求页面”是前端路由原理的核心之一,完成主要有两种方法
hash—-使用URL中的hash(“#”)
使用Historyinterface在HTML5中新增的方法
完成方法首先在router/index.js中注册路由Vue.use(Router)
这儿把路由独自写在一个routes.js中并导出,注意别忘了导出exportdefaultroutes
constroutes=[
{
path:’/’,
redirect:’/routerTest’
},
{
path:’/routerTest’,
component:()=>import(‘../components/recommend/view.vue’)
},
{
path:’/singer’,
component:()=>import(‘../components/singer/view.vue’)
},
{
path:’/rank’,
component:()=>import(‘../components/rank/view.vue’)
},
{
path:’/search’,
component:()=>import(‘../components/search/view.vue’)
}
]
exportdefaultroutes
importVuefrom’vue’
importRouterfrom’vue-router’
importroutesfrom’./routes’
Vue.use(Router)
exportdefaultnewRouter({
//mode:’history’,//两种形式hash和history
routes
})
这两种方法有什么区别呢
1.mode:’hash’多了个#前端路由不刷新页面
http://localhost:8080/#/routerTest
2.mode:’history’会去恳求接口
http://localhost:8080/routerTest
来看下完成不同形式跳转路由的源码
//根据mode确认history实践的类并实例化
//根据mode确认history实践的类并实例化
switch(mode){
case’history’:
this.history=newHTML5History(this,options.base)
break
case’hash’:
this.history=newHashHistory(this,options.base,this.fallback)
break
case’abstract’:
this.history=newAbstractHistory(this,options.base)
break
default:
if(process.env.NODE_ENV!==’production’){
assert(false,`invalidmode:${mode}`)
}
}
HashHistory和HTML5History有什么区别
hashhistory将路由添加到浏览器的栈顶push
html5history将路由在浏览器中替换replace
以上是vue-router的完成原理,接下来如何在项目中使用vue-router呢
vue的router-link和router-view,是完成vue-router的两个必不可缺的组件,分别完成跳转路由和展现路由
首先在main.js进口文件中配置router实例
举个栗子
点击跳转C就切换到了LayOut组件的页面vue-router

vue-router的实现原理

之前用Vue开发单页运用,发现不管路由怎样改动,浏览器地址栏总是会有一个’#’号。
其时检查自己的代码,没有发现恳求的地址带’#’,其时也很疑惑,但是因为没有影响页面的烘托以及向后台发送恳求,其时也没有介意。最近看了一下vue-router的完成原理,才逐步揭开了这个谜题。
vue-router的两种方式(浏览器环境下)
1.Hash(对应HashHistory)
hash(“#”)符号的本来效果是加在URL中指示网页中的位置:
http://www.example.com/index.html#print
#符号本身以及它后边的字符称之为hash(也便是我之前为什么地址栏都会有一个‘#’),可经过window.location.hash特点读取。它具有如下特色:
hash尽管出现在URL中,但不会被包含在HTTP恳求中。它是用来指导浏览器动作的,对服务器端完全无用,因而,改动hash不会从头加载页面
2.能够为hash的改动增加监听事情:
1
window.addEventListener(“hashchange”,funcRef,false)
每一次改动hash(window.location.hash),都会在浏览器的访问历史中增加一个记录
运用hash的以上特色,就能够来完成前端路由“更新视图但不从头恳求页面”的功用了。
2.History(对应HTML5History)
History接口是浏览器历史记录栈供给的接口,经过back(),forward(),go()等办法,咱们能够读取浏览器历史记录栈的信息,进行各种跳转操作。
从HTML5开始,Historyinterface供给了两个新的办法:pushState(),replaceState()使得咱们能够对浏览器历史记录栈进行修正:
window.history.pushState(stateObject,title,URL)
window.history.replaceState(stateObject,title,URL)
stateObject:当浏览器跳转到新的状况时,将触发popState事情,该事情将携带这个stateObject参数的副本title:所增加记录的标题URL:所增加记录的URL
这两个办法有个一起的特色:当调用他们修正浏览器历史记录栈后,尽管当时URL改动了,但浏览器不会刷新页面,这就为单页运用前端路由“更新视图但不从头恳求页面”供给了基础。浏览器历史记录能够看作一个「栈」。栈是一种后进先出的结构,能够把它幻想成一摞盘子,用户每点开一个新网页,都会在上面加一个新盘子,叫「入栈」。用户每次点击「撤退」按钮都会取走最上面的那个盘子,叫做「出栈」。而每次浏览器显示的天然是最顶端的盘子的内容。
vue-router的效果
vue-router的效果便是经过改动URL,在不从头恳求页面的情况下,更新页面视图。简单的说便是,尽管地址栏的地址改动了,但是并不是一个全新的页面,而是之前的页面某些部分进行了修正。
exportdefaultnewRouter({
//mode:’history’,//后端支持可开
routes:constantRouterMap
})
这是Vue项目中常见的一段初始化vue-router的代码,之前没仔细研讨过vue-router,不知道还有一个mode特点,后来看了相关文章后了解到,mode特点用来指定vue-router运用哪一种形式。在没有指定mode的值,则运用hash形式。
源码剖析
首先看一下vue-router的结构函数
constructor(options:RouterOptions={}){
this.app=null
this.apps=[]
this.options=options
this.beforeHooks=[]
this.resolveHooks=[]
this.afterHooks=[]
this.matcher=createMatcher(options.routes||[],this)
letmode=options.mode||’hash’
this.fallback=mode===’history’&&!supportsPushState&&options.fallback!==false
if(this.fallback){
mode=’hash’
}
if(!inBrowser){
mode=’abstract’
}
this.mode=mode
switch(mode){
case’history’:
this.history=newHTML5History(this,options.base)
break
case’hash’:
this.history=newHashHistory(this,options.base,this.fallback)
break
case’abstract’://非浏览器环境下
this.history=newAbstractHistory(this,options.base)
break
default:
if(process.env.NODE_ENV!==’production’){
assert(false,`invalidmode:${mode}`)
}
}
}
主要是先获取mode的值,假如mode的值为history但是浏览器不支持history形式,那么就强制设置mode值为hash。假如支持则为history。接下来,依据mode的值,来选择vue-router运用哪种形式。
case’history’:
this.history=newHTML5History(this,options.base)
break
case’hash’:
this.history=newHashHistory(this,options.base,this.fallback)
break
这样就有了两种形式。确认好了vue-router运用哪种形式后,就到了init。先来看看router的init办法就干了哪些事情,在src/index.js中
init(app:any/*Vuecomponentinstance*/){
//….
consthistory=this.history
if(historyinstanceofHTML5History){
history.transitionTo(history.getCurrentLocation())
}elseif(historyinstanceofHashHistory){
constsetupHashListener=()=>{
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)
}
}
假如是HTML5History,则履行
1
history.transitionTo(history.getCurrentLocation())
假如是Hash形式,则履行
constsetupHashListener=()=>{
history.setupListeners()
}
history.transitionTo(
history.getCurrentLocation(),
setupHashListener,
setupHashListener
)
能够看出,两种形式都履行了transitionTo()函数。接下来看一下两种形式分别是怎样履行的,首先看一下Hash形式
HashHistory.push()
咱们来看HashHistory中的push()办法:
push(location:RawLocation,onComplete?:Function,onAbort?:Function){
this.transitionTo(location,route=>{
pushHash(route.fullPath)
onComplete&&onComplete(route)
},onAbort)
}
functionpushHash(path){
window.location.hash=path
}
transitionTo()办法是父类中界说的是用来处理路由改动中的基础逻辑的,push()办法最主要的是对window的hash进行了直接赋值:
window.location.hash=route.fullPathhash的改动会主动增加到浏览器的访问历史记录中。
那么视图的更新是怎样完成的呢,咱们来看父类History中transitionTo()办法的这么一段:
transitionTo(location:RawLocation,onComplete?:Function,onAbort?:Function){
//调用match得到匹配的route目标
constroute=this.router.match(location,this.current)
this.confirmTransition(route,()=>{
this.updateRoute(route)

})
}
updateRoute(route:Route){
this.cb&&this.cb(route)
}
listen(cb:Function){
this.cb=cb
}
能够看到,当路由改动时,调用了History中的this.cb办法,而this.cb办法是经过History.listen(cb)进行设置的。回到VueRouter类界说中,找到了在init()办法中对其进行了设置:
init(app:any/*Vuecomponentinstance*/){
this.apps.push(app)
history.listen(route=>{
this.apps.forEach((app)=>{
app._route=route
})
})
}
代码中的app指的是Vue的实例,._route本不是本身的组件中界说的内置特点,而是在Vue.use(Router)加载vue-router插件的时分,经过Vue.mixin()办法,全局注册一个混合,影响注册之后一切创建的每个Vue实例,该混合在beforeCreate钩子中经过Vue.util.defineReactive()界说了呼应式的_route。所谓呼应式特点,即当_route值改动时,会主动调用Vue实例的render()办法,更新视图。vm.render()是依据当时的_route的path,name等特点,来将路由对应的组件烘托到.所以总结下来,从路由改动到视图的更新流程如下:
this.$router.push(path)
–>
HashHistory.push()
–>
History.transitionTo()
–>
constroute=this.router.match(location,this.current)会进行地址匹配,得到一个对应当时地址的route(路由信息目标)
–>
History.updateRoute(route)
–>
app._route=route(Vue实例的_route改动)因为_route特点是选用vue的数据绑架,当_route的值改动时,会履行呼应的render()
–>
vm.render()具体是在中render
–>
window.location.hash=route.fullpath(浏览器地址栏显示新的路由的path)
HashHistory.replace()
说完了HashHistory.push(),该说HashHistory.replace()了。
replace(location:RawLocation,onComplete?:Function,onAbort?:Function){
this.transitionTo(location,route=>{
replaceHash(route.fullPath)
onComplete&&onComplete(route)
},onAbort)
}
functionreplaceHash(path){
consti=window.location.href.indexOf(‘#’)
window.location.replace(
window.location.href.slice(0,i>=0?i:0)+’#’+path
)
}
能够看出来,HashHistory.replace它与push()的完成结构上根本相似,不同点在于它不是直接对window.location.hash进行赋值,而是调用window.location.replace办法将路由进行替换。这样不会将新路由增加到浏览器访问历史的栈顶,而是替换掉当时的路由。
监听地址栏
能够看出来,上面的进程都是在代码内部进行路由的改动的,比方项目中常见的this.$router.push(),等办法。然后将浏览器的地址栏置为新的hash值。那么假如直接在地址栏中输入URL从而改动路由呢,例如
我将dashboadr删除,然后置为article/hotSpot,然后回车,vue又是如何处理的呢?
setupListeners(){
window.addEventListener(‘hashchange’,()=>{
if(!ensureSlash()){
return
}
this.transitionTo(getHash(),route=>{
replaceHash(route.fullPath)
})
})
}
该办法设置监听了浏览器事情hashchange,调用的函数为replaceHash,即在浏览器地址栏中直接输入路由相当于代码调用了replace()办法.后边的过程天然与HashHistory.replace()相同,一样完成页面烘托。
HTML5History
HTML5History形式的vue-router代码结构以及更新视图的逻辑与hash形式根本相似,和HashHistory的过程根本一致,只是HashHistory的push和replace()变成了HTML5History.pushState()和HTML5History.replaceState()
在HTML5History中增加对修正浏览器地址栏URL的监听是直接在结构函数中履行的,对HTML5History的popstate事情进行监听:
constructor(router:Router,base:?string){
window.addEventListener(‘popstate’,e=>{
constcurrent=this.current
this.transitionTo(getLocation(this.base),route=>{
if(expectScroll){
handleScroll(router,route,current,true)
}
})
})
}
以上便是vue-routerhash形式与history形式不同形式下处理逻辑的剖析了。
总结
以上所述是小编给我们介绍的vue-router完成原理及两种形式剖析,希望对我们有所协助!

未经允许不得转载:IT技术网站 » vue-router(vue-router的实现原理)
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!

 

志在指尖 用双手敲打未来

登录/注册IT技术大全

热门IT技术

C#基础入门   SQL server数据库   系统SEO学习教程   WordPress小技巧   WordPress插件   脚本与源码下载