手写VueRouter

定义VueRouter类

export default class VueRouter {
//构造函数中把参数存储下来
constructor(options) {
    this.options = options
    this.routeMap = {}//用于存储路由对应的view组件
    const cur =
      (this.options.mode === 'history'
        ? location.pathname
        : location.href.split('#')[1]) || '/'/*当前路由
若是history模式,则直接取pathname,否则解析出#后面的内容作为路由*/
    this.data = _Vue.observable({
      current: cur,
    })
}

实现静态方法install

在里面需要判断插件是否安装,安装了则什么也不做,否则注入实例

static install(vue) {
    //判断当前插件是否已安装
    if (VueRouter.install.isinstalled) {
      return
    }
    VueRouter.install.isinstalled = true
    //把vue构造函数记录到全局变量
    _Vue = vue
    //把创建vue实例时传入的router对象注入到vue实例上
    _Vue.mixin({
      beforeCreate() {
        if (this.$options.router) {
          _Vue.prototype.$router = this.$options.router
          this.$options.router.init()
        }
      },
    })
  }
  init() {
    this.createRouteMap()//建立路由和view的映射关系
    this.initComponents(_Vue)//component渲染
    this.initEvent()//浏览器事件处理
  }

存储路由对应的组件

//解析路由规则为键值对形式,存储到实例的routemap 中
  createRouteMap() {
    this.options.routes.forEach((route) => {
      this.routeMap[route.path] = route.component
    })
  }

处理router-link,router-view

initComponents(Vue) {
    let self = this
    Vue.component('router-link', {
      props: {
        to: String,
      },
      render(h) {
        return h(
          'a',
          {
            attrs: {
              href: this.to,
            },
            on: {
              click: this.handleClick,//绑定事件
            },
          },
          [this.$slots.default],
        )
      },
      methods: {
        handleClick(e) {
          if (self.options.mode === 'history') {
            history.pushState({}, '', this.to)
            this.$router.data.current = this.to
          } else {
            location.hash = this.to
            this.$router.data.current = this.to.split('#')[1]
          }

          e.preventDefault()
        },
      //template: '<a :href="to"><slot></slot></a>',
    })

    Vue.component('router-view', {
      render(h) {
        let component = self.routeMap[self.data.current]
        return h(component)
      },
    })
  }

浏览器前进后退事件处理

根据不同模式监听不同的浏览器事件

//注册事件
  initEvent() {
    //history模式
    if (this.options.mode === 'history') {
      window.addEventListener('popstate', () => {
        this.data.current = location.pathname
      })
    } else {
      //hash模式
      window.addEventListener('hashchange', () => {
        this.data.current = location.hash.substring(1)
      })
    }
  }

相关文章

https://segmentfault.com/a/1190000022018995 https://www....
ES6 (ECMAScript 6)中的模块是一个包含 JavaScript 代码的...
from https://mp.weixin.qq.com/s/-rc1lYYlsfx-wR4mQmIIQQ V...
D:\Temp&gt;npm init vite@latest vue3study --temp...
文章浏览阅读1.2k次。最近自己从零撸起的甘特图组件需要子组...
文章浏览阅读3.3k次,点赞3次,收藏16次。静默打印是什么?简...