vue: vueRouter实现原理

vuerouter的使用

在这里插入图片描述

在这里插入图片描述

根据类图进行分析

在这里插入图片描述

options记录构造函数传递的对象 routers
data中有个属性current,用来记录当前路由地址(data是响应式的)
routeMap 记录组件和路由的关系

install静态方法
constructor用来初始化属性
initEvent用来注册popState事件,监听浏览器地址的变化
createRouteMap 把构造函数中的路由规则以键值对存储在routerMap对象中
initComponents用来创建 router-link和router-view两个组件的

history模式的原理

在这里插入图片描述

实现

/src/VueRouter/index.js

let _Vue = null
export default class vueRouter {
  static install (Vue) {
    // 1)判断当前插件是否被安装
    if(vueRouter.install.installed) {
      return
    }
    vueRouter.install.installed = true // 表示插件已安装
    // 2) 把vue构造函数记录到全局变量 (将来要在实例中使用该构造函数)
    _Vue = Vue
    // 3)把创建Vue实例时候传入的router对象注入到Vue实例上
    // 混入
    _Vue.mixin({
      beforeCreate() {
        console.log('this.$options.router111', this.$options.router)
        if(this.$options.router) {
          _Vue.prototype.$router = this.$options.router // 在mixin中this指向的就是实例
          console.log(' this.$options.rotuer000',  this.$options.router.init)
          this.$options.router.init()
        }
      }
    })
  }
  constructor(options) {
    this.options = options
    this.routeMap = {}
    console.log(' _Vue.observable',  _Vue.observable)
    this.data = _Vue.observable({
      current: '/' // 默认下是斜杠
    }) //vue的observable方法用来创建响应式对象
  }

  init() {
    this.createRouteMap()
    this.initComponents(_Vue)
    this.initEvent()
  }

  createRouteMap() {
    console.log('createRouteMap', this.options.routers)
    // 遍历所有的路由规则
    this.options.routes.forEach(route => {
      this.routeMap[route.path] = route.component
    })
  }

  initComponents(Vue) {
    Vue.component('router-link', {
      props: {
        to: String
      },
      render(h) {
      console.log('router-link重新渲染, 首次加载才会触发router-link渲染')
        return h('a', {
          attrs: {
            href: this.to
          },
          on: {
            click: this.handleClik
          }
        }, [this.$slots.default])
      },
      methods: {
        handleClik(e) {
          history.pushState({}, '',this.to)
          this.$router.data.current = this.to // data的current是响应式的,页面会同步改变的
          e.preventDefault() //并不希望点击链接后发生跳转并向服务器发送请求
        }
      }
      // template: '<a href="to"><slot>/slot<></a>' // 运行时版本vue不支持template选项的,需要转换成render函数
    })
    const self = this
    Vue.component('router-view', {
      render(h) {
        console.log('router-view重新渲染--每次current改变都会触发该render函数', self.data.current)
        const component = self.routeMap[self.data.current]
        return h(component)
      }
    })
  }
  initEvent() { //解决点击浏览器的前进后退,组件没有更新的问题
    window.addEventListener('popstate', () => {
     console.log('popstate触发--点击地址栏前进后退才会触发')
      this.data.current = window.location.pathname
    })
  }
}

/src/router/index.js
在这里插入图片描述
/vue.config.js
使用vue的编译版本

module.exports = {
  runtimeCompiler: true
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值