2016-10-20 13:51:24

从Vue 1.0到Vue 2.0: 博客升级记录

Vue 2.0的官方升级文档十分全面, 但仅局限于API, 有些细节之处并没有谈到. 本文作为博客的升级博文, 持续记录一下Vue 1.0升级到2.0的一些操作

vue-cli说明

vue-cli项目的升级方法, 尤大正在做, 因此现在需要我们手动升级依赖

更新依赖包

我的博客前端由两个SPA构成: 前台和后台管理. 它们都是用vue-cli脚手架搭好的

需要注意, vue-cli依赖vue-loader, 文档里并没有写vue-loader也要升级

npm install --save vue@2.0.3 vue-router@2.0.1
npm install --save-dev vue-loader@next

vue-loader适配vue2的版本号为9.x, 但是npm中主线版本仍然为8.x, 因此需要用@next来安装

之后npm run dev,SPA显示的应该是一个白屏

官方迁移工具

现在该修改源码了.

官方提供了一个迁移工具, 它会分析源码中已经变更了的API, 并提供建议与实例的链接

npm install --global git://github.com/vuejs/vue-migration-helper.git

之后进入SPA的源码文件夹

vue-migration-helper

详细的升级信息已经输出, 按照对应的说明和链接进行修改即可

第一个问题

执行一下npm run dev, 然而显示的仍然是一个白屏.

先说解决办法, 再研究原因

解决办法

  • index.html中的所有vue模板剪贴至一个新组件内
  • 在入口文件中导入刚刚那个组件, 为了调试方便, 最好将其全局注册一下
  • router.start语句更改为
    new Vue({
      router,
      render: h => h(App)
    }).$mount('#app')
    
  • buildack.dev.conf.js的模块导出中添加如下语句
    resolve: {
      alias: {vue: 'vue/dist/vue.js'}
    },
    

现在npm run dev, 首屏应该可以正确显示了

原因

vue2使用了虚拟DOM, 需要一次转换才可以将index.html中的模板成功转换成html

而vue2分为两种, 一种是build, 另一种就是vue-cli依赖的runtime

build直接支持上面说的那种转换, 然而代价是体积比runtime大整整一半

不过没关系, 最后构建是用的runtime版本, dev模式下用build版没有任何问题

第二个问题

这个问题比较小, 但是它代表了vue2.0的一个重要变化

设置标签的属性时, 必须用v-bind指令, 不再支持模板

<router-view to="">为例, 如果to属性是一个对象, 那么必须用v-bind来将其绑定

第三个问题

vue-router生命周期好多都被取消了, 比如重要的data, 然而官方迁移工具并没提到这一点.

现在要求用watch来做跳转, 不要忘了watch函数的参数, 很好用.

    watch: {
    '$route': 'fetchData'
    },
    methods: {
        fetchData: function(val, oldVal) {
             console.log(val, oldVal);
      }
    },

第四个问题

vue-router2的h5模式开启后, F5强制刷新并不会触发watch, 我们需要利用vue-router2的钩子函数来解决这个问题.

vue-router2适合这种场景的钩子函数有三种

  • 全局beforeEach
  • 路由钩子beforeEnter
  • 组件级beforeRouteEnter

这里采用组件级钩子函数beforeRouteEnter

beforeRouteEnter (to, from, next) {
      next(vm => {
          vm.fetchData();
      })
  },

beforeRouteEnter钩子不能通过this来拿组件内部的属性和方法, 因为此时组件甚至还未挂载好.但是, 可以给next设置一个回调, 因为这个回调的参数就是组件的this.

这里还有一个小问题, 路由内含有小数点时, 浏览器直接返回404而不是由vue-router控制, 待解决

禁止缓存组件

vue2的数据响应比我想象中要坑不少。有如下一个场景:

同一个echarts图表子组件被v-for指令渲染了两次,当子组件初始化完毕后,修改传给第二个子组件的数据,然而它并没有变化。

出现这个问题后,排查了很久确定不是echarts的锅,可能是组件被vue2缓存了,因此将这个子组件用不同名称导入了两次,临时解决了这个问题。

仔细查询API文档后,发现一个key属性,当它变化时组件必然变化,并触发组件生命周期,因此能够强制禁止掉组件的缓存。

组件的@click.native

vue2组件的点击事件必须用@click.native,否则@click传的只是一个方法。我不评价这种做法是否合适,不过Element团队选择对Button组件进行优化,即Button的@click也可以监听到原生点击

主要变化

  • 单向数据流
    • vue1.0的sync和once这种双向绑定还是挺好用的.react提供双向绑定的选项, 不知道vue2有没有.
  • 组件生命周期的变化, 比如ready变为mounted
  • 设置标签的属性时, 必须用v-bind指令, 不再支持模板
  • vue-router的API更加整洁, 几乎所有选项都被放入到构造函数中
  • v-link属性配合a标签, 变更为to属性配合router-link 标签, 和react-router一模一样

本文链接:https://smallpath.me/post/vue-upgrade-2

-- EOF --