Vue Router 实现原理

Vue Router 实现原理

会用到以下几个前置知识

  • 插件
  • 混入
  • Vue.observable()
  • 插槽
  • render 函数
  • 运行时和完整版的 Vue

概念

当前端路由切换的时候,在浏览器端判断当前路径,并加载当前路径对应的组件

Hash 模式

  • URL 中 # 后面的内容作为路径地址
  • 监听 hashchange 事件
  • 根据当前路由地址找到对应组件重新渲染

History 模式

  • 通过 history.pushState() 改变地址栏,不会向服务器发送请求
  • 监听 prpstate 事件
  • 根据当前路由地址找到对应组件重新渲染

简易版 Vue Router

// history 模式
// 新建一个 js 文件并导出一个 vueRouter 类
let _Vue = null
export default class VueRouter {
   static install (Vue) {
    // 接收两个参数,第一个 Vue 构造器,第二个可选的 options 对象
    // 1. 判断当前插件是否已经安装
    if(VueRouter.install.installed) return
    VueRouter.install.installed = true
    // 2. 把 Vue 构造函数记录到全局变量
    _Vue = Vue
    // 3. 把创建 Vue 实例的时候传入的 router 对象注入到 Vue 实例上
    _Vue.mixin({
        beforeCreate () {
            if(this.$options.router) {
                _Vue.prototype.$router = this.$options.router
                this.$options.router.init()
            }
        }
    })
   } 
   
   constructor (options) {
       this.options = options
       this.routeMap = {}
       this.data = _Vue.observable({
           current: '/'
       })
   }
   
   init () {
       this.createRouteMap()
       this.initComponents(_Vue)
       this.initEvent()
   }
   
   createRouteMap () {
       // 遍历所有的路由规则,把路由规则解析成键值对的形式存储到 routeMap 中
       this.options.routes.forEach(route => {
           this.routeMap[route.path] = route.component
       })
   }
   
   initComponents (Vue) {
       Vue.component('router-link', {
           props: {
               to: String
           },
           // template: '<a :href="to"><slot></slot></a>'
           render (h) {
               return h('a', {
                   attrs: {
                       href: this.to
                   },
                   on: {
                       click: this.clickHandler
                   }
               }, [this.$slots.default])
           },
           methods: {
               clickHandler (e) {
                   history.pushState({}, '', this.to)
                   this.$router.data.current = this.to
                   e.preventDefault()
               }
           }
       })
       const self = this
       Vue.component('router-view', {
           render(h) {
                const component = self.routeMap[self.data.current]
                return h(component)
           }
       })
   }
   
   initEvent () {
       window.addEventListener('popstate', () => {
           this.data.current = window.location.pathname
       })
   }
}
posted @ 2022-06-01 17:53  地灵  阅读(50)  评论(0编辑  收藏  举报