美文网首页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