vue-router 原理及实现
vue-router作为Vue全家桶实现spa的重要部分主要实现以下功能:
当页面url发生变化,不刷新页面,只改变渲染的组件(通过hash,或者history api)
拆分为以下三部分
1.监听url发生变化,并将url加入响应式数据,使得其他组件会重新执行render
2.提供router-view组件充当占位容器,当url发生变化,更新内部组件
3.提供router-link组件用于路由切换
实现:
1.创建Class VueRouter,并监听hash变化
class VueRouter { constructor(options){ this.options =options //数据响应式,current必须是响应式的,这样他变化,使用他的组件就会更新render //利用Vue.util.defineReactive实现响应式 Vue.util.defineReactive(this,'current',window.location.hash.slice(1)||'/') //监控url变化 window.addEventListener('hashchange',()=>{ this.current = window.location.hash.slice(1) }) } }
export default VueRouter
2.注册router-view和router-link组件
//Vue插件要实现一个install方法,当Vue.use(VueRouter)时会调用install方法 VueRouter.install =function(_Vue){ //注册router实例 Vue = _Vue //通过全局混入: Vue.mixin({beforeCreate}) Vue.mixin({ beforeCreate(){ //仅在根组件创建时执行一次,从而获取根组件传入的router,从而获取路由表routes用于获取router-view所需渲染的组件 if(this.$options.router){ Vue.prototype.$router= this.$options.router } } }) //注册router-view和router-link Vue.component('router-view',{ render(h){ //通过url得到对应的component 并渲染 let component =null const {current,options}=this.$router //根据监听url得到的current从路由表routes中筛选出需要渲染的component const route= options.routes.find(route=>route.path===current) if(route){ component = route.component } return h(component) } }) Vue.component('router-link',{ props:{ to:{ type:String, require:true } }, render(h){ //通过传入的to渲染前往对应路由的a标签 return h('a',{attrs:{href:'#'+this.to}},this.$slots.default) } }) }
完整代码
let Vue class VueRouter { constructor(options){ this.options =options Vue.util.defineReactive(this,'current',window.location.hash.slice(1)||'/') window.addEventListener('hashchange',()=>{ this.current = window.location.hash.slice(1) }) } } VueRouter.install =function(_Vue){ Vue = _Vue Vue.mixin({ beforeCreate(){ if(this.$options.router){ Vue.prototype.$router= this.$options.router } } }) Vue.component('router-view',{ render(h){ let component =null const {current,options}=this.$router const route= options.routes.find(route=>route.path===current) if(route){ component = route.component } console.log(current,options); return h(component) } }) Vue.component('router-link',{ props:{ to:{ type:String, require:true } }, render(h){ return h('a',{attrs:{href:'#'+this.to}},this.$slots.default) } }) } export default VueRouter