手写vue-router之history模式【四、具体实现二】

90 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第24天,点击查看活动详情

前情提要

  • 不知道小伙伴有没有将真正的vue-router插件替换上一篇中写的那个demo?
  • 替换过并运行的小伙伴会发现一个问题,控制台报错了。

运行demo

  • 首先咱们写好router插件之后我们再另外创建一个文件夹:routerConfig,然后在文件夹下创建一个文件:index.js。主要用来配置我的项目中的路由信息。 WX20220623-010636@2x.png
  • 然后在views中创建两个vue页面级组件,为了节省时间每个组件只展示不同的字符串。 WX20220623-010839@2x.png
  • 之后我们在app.vue中做个小小的修改: WX20220623-010702@2x.png
  • 然后我们就可以跑起来了。不出意外的话一定会出意外了。
  • 我们发现点击首页的按钮之后,页面地址栏没有发生跳转,页面没有反应。
  • 打开控制台一看,好家伙,报错了。 WX20220623-011020@2x.png
  • 从报错信息中可以看出是因为router-link组件没有正确注册,vue无法识别。这是为什么?我们明明写的没有问题的...

运行时和编译器

  • 造成上述问题的根本原因是Vue的构建版本问题。vue的构建版本分为:运行时版本和完整版版本。
    • 运行时版本:不支持template模板,需要打包的时候提前编译。
    • 完整版本:包含运行时和编译器。不过相对应的体积也会增加10k左右,程序运行的时候会把模板转化成render函数。

怎么解决这个问题呢?

render

  • 修改我们造的轮子router中的initComponents

    // 原来的:
    initComponents(Vue) { 
        Vue.component('router-link', { 
            props: { to: String }, 
            template: '<a :href="to"><slot></slot></a>' 
        }) 
    }
    // 改成:
    initComponents(Vue) {
      Vue.component(
        'router-link', 
        {
          props: {
              to: String
          },
          render(h) {
            return h('a', { attrs: { href: this.to } }, [ this.$slots.default ])
          }
        }
      )
    }
    
  • 然后我们重启项目可以看到router-link已经被渲染成a标签了 WX20220623-013923@2x.png

修改vue-cli配置

  • 如果上面的我们不做改动,该如何解决这个问题呢?
  • 从vue-cli官网可以看到,我们可以在vue.config.js文件中配置runtimeCompiler为true开启完整版Vue构建版本来解决这个问题: image.png
  • 从开发者工具中我们可以看到,router组件依然被正确编译成a标签了 image.png

  • 对于h函数的方法的使用方式有很多,有兴趣的小伙伴可以自行查阅。后期可能会出关于h函数使用的相关文章。