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

 

posted on 2021-12-24 11:26  ShawYoi  阅读(435)  评论(0编辑  收藏  举报