美文网首页vue
Vue Router简单模拟实现

Vue Router简单模拟实现

作者: 浅忆_0810 | 来源:发表于2021-07-05 23:04 被阅读0次

1. Vue的构建版本

  • 运行时版:不支持template模板,需要打包的时候提前编译
  • 完整版:包含运行时和编译器,体积比运行时版大10K左右,程序运行的时候把模板转换成render函数

2. Vue Router history模式实现

2.1 回顾vue router核心代码

// 注册插件
// vue.use() 内部调用传入对象的 install 方法

Vue.use(VueRouter)
// 创建路由对象
const router = new VueRouter({
  routes: {
    { name: 'home', path: '/', component: homeComponent }
  }
});
// 创建 Vue 实列,注册 router 对象
new Vue({
  router,
  render: h => h(App)
}).$mount('#app')

2.2 实现思路

  1. 创建 VueRouter 插件,静态方法 install
    • 判断插件是否已经被加载
    • Vue加载的时候把传入的 router对象挂载到 Vue实例上(注意:只执行一次)
  2. 创建 VueRouter
    • 初始化,optionsrouteMapdata(响应式数据记录当前路径)
    • initRouteMap()遍历所有路由信息,把组件和路由的映射记录到routeMap对象中
    • 注册popstate事件,当路由地址发生变化,重新记录当前的路径
    • 创建router-linkrouter-view组件
    • 当路径改变的时候通过当前路径在routeMap对象中找到对应的组件,渲染router-view
let _Vue = null
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() {
        if (this.$options.router) {
          // 把 router 对象是注入到 Vue 实例上
          _Vue.prototype.$router = this.$options.router;
          // 初始化插件的时候 调用 init
          this.$options.router.init();
        }
      }
    })
  }

  constructor(options) {
    this.options = options;
    // 记录路径和对应的组件
    this.routeMap = {};
    this.data = _Vue.observable({
      current: '/' // 当前的默认路径
    })
    this.init()
  }

  init() {
    this.initRouteMap()
    this.initComponent(_Vue)
    this.initEvent()
  }

  initRouteMap() {
    // 遍历所有的路由规则 把路由规则解析成键值对的形式存储到routeMap中
    this.options.routes.forEach(route => {
      this.routeMap[route.path] = route.component
    });
  }

  initComponent(Vue) {
    Vue.component('router-link', {
      props: {
        to: String
      },
      // 需要带编译器版本的 Vue.js
      // template:"<a :href='to'><slot></slot></a>"
      // 使用运行时版本的 Vue.js
      render(h) {
        return h('a', {
          attrs: {
            href: this.to
          },
          on: {
            click: this.clickhander
          }
        }, [this.$slots.default])
      },
      methods: {
        clickhander(e) {
          history.pushState({}, '', this.to)
          this.$router.data.current = this.to
          e.preventDefault()
        }
      }
    })

    const self = this
    Vue.component("router-view", {
      render(h) {
        // 根据当前路径找到对应的组件,注意 this 的问题
        const cm = self.routeMap[self.data.current]
        return h(cm)
      }
    })
  }

  initEvent() {
    // 当路径变化之后,重新获取当前路径并记录到 current
    window.addEventListener("popstate", () => {
      this.data.current = window.location.pathname
    })
  }
}

注意:

  1. vue-cli创建的项目默认使用的是运行时版本的 Vue.js

  2. 如果想切换成带编译器版本的Vue.js,需要修改vue-cli配置

    • 项目根目录创建vue.config.js文件,添加runtimeCompiler

      module.exports = {
        runtimeCompiler: true
      }
      

学习文章1

学习文章2

相关文章

网友评论

    本文标题:Vue Router简单模拟实现

    本文链接:https://www.haomeiwen.com/subject/aapdultx.html