本篇文章记录了完整的前端 Vue1.x 项目迁移至 Vue2.x 的步骤和遇到的问题。并且在迁移的过程也对Vue进行进一步学习。
1 为什么要迁移 Vue2.x
由于项目后面希望用到饿了么的 vue 组件,而且当前很多组件都是基于 Vue2.x 的,对于 Vue1.x 都已经不再维护。
Vue2.x 更加成熟,并且后面准备在移动端接入 weex ,而 weex 中也推荐使用 Vue2.x 进行开发。
综上所述,下定决心开始对 Vue1.x 的项目进行迁移。
2 前期准备
先介绍下原有项目的大致情况。
- 项目不是单纯的单页面应用,每个大模块是一个单页面应用,大模块中的子模块的跳转使用路由进行跳转。
- 原有项目 vue 版本号1.0.21,vue-router 版本号0.7.13,未使用 vuex ,网络请求用的就是 jquery
希望在迁移后,新功能的添加可以完全使用单页面应用,并且配合用上 vuex 和网络请求库( axios )还有一些其他的插件。
现附上在迁移过程中相关文档地址:
- 这也是迁移过程中主要的参考文档
- 官方迁移的辅助工具,用以遍历查找出需要迁移的地方。识别出旧有的特性后,就会告知并给出建议,同时附上关于详细信息的链接。
- 万能的 Google
3 开始迁移
3.1 检查出迁移的地方
先安装官方迁移工具
npm install --global vue-migration-helper复制代码
安装完成后进入项目目录,扫描项目中文件找出需要迁移的代码位置。(并不能完全找出,但是可以解决大部分的迁移)
我的迁移做法是扫描全局后,专注修改一类迁移问题,修改完后commit并且再次扫描确认该类问题已经解决。然后再解决下一类的问题。
第一次扫描并输出到文件中
vue-migration-helper >a.log复制代码
输出一看,WTF!!!500多个迁移点,网上人家迁移就几十个迁移点。呵呵哒了。
3.2 package.json修改
首先提示的是修改 package.json 中的版本号,并重新 npm install
这个没啥,我直接升到了最新的vue和vue-router版本
3.3 v-link 替换
第一个解决的是 v-link
提示信息如下
找到相关文档
文档描述是把
About复制代码
替换成
About 复制代码
But,项目中是这么写的
复制代码
查询最新的 vue-router 文档,可以使用编程式导航,改成如下
复制代码
然后查找所有 v-link
类型问题一个个全部改过来,commit 提交。重新扫描一次。
3.4 $index 和 $key 的移除
$index
和 $key
的移除问题的提示是这样的
文档见
主要是 Vue2.x 中移除了隐变量 $index
和 $key
,全部显示声明。修改例子如下
{ { $index+1 }}复制代码
改为:
{ { index+1 }}复制代码
回头重新看了下 v-for
的文档
默认命名 index
代表索引,key
代表遍历对象的键值。
比如遍历一个数组的时候,第二个参数是 index
索引
- { { parentMessage }} - { { index }} - { { item.message }}
当遍历对象时,第二个参数是 key
键
{ { key }} : { { value }}复制代码
同时如果遍历对象,还可以有第三个参数代表索引
{ { index }}. { { key }} : { { value }}复制代码
3.5 HTML 的计算插值移除 ({ { { }}})
HTML 的计算插值移除 提示是这样的
文档见
这个替换比较简单,就是把 { { {}}}
全部替换为 v-html
3.6生命周期 ready 替换
生命周期 ready 替换 提示是这样的
要把生命周期钩子函数 ready
替换为以下:
mounted: function () { this.$nextTick(function () { // 代码保证 this.$el 在 document 中 })}复制代码
在这里我回头看了下 nextTick
的具体概念:
意思就是当数据发生变化后 DOM 不会立即更新,而是会在一个更新周期时统一更新(感觉就像 Android 的16ms 渲染刷新)。所以使用 nextTick
,是一个异步执行,意思是方法里面的代码会在下次 DOM 更新后执行。
3.7 Array-prototype-$remove 移除
Array-prototype-$remove 移除问题的提示:
文档见
数组的一个 remove
方法移除了,换成了 splice
方法。
vm.articleList.$remove(vm.temArticle)复制代码
改成
var index = vm.articleList.indexOf(vm.temArticle);vm.articleList.splice(index, 1)复制代码
3.8 v-el 和 v-ref 替换
v-el
和 v-ref
替换问题的提示:
文档见:
直接全局将 v-el
和 v-ref
换成 ref
3.9 属性内部的计算插值移除 ({ { }})
属性内部的计算插值移除的提示:
文档见:
属性内部的计算插值已经不能再使用了:
复制代码
应该写成行内表达式:
复制代码
3.10 v-for 遍历数组/对象时的参数顺序变更
v-for
遍历数组/对象时的参数顺序变更问题的提示:
文档见:
当包含 index
key
时,之前遍历数组时的参数顺序是 (index, value)
。现在是 (value, index)
, 目的为了和 Javascript 原生中的顺序保持一致。
3.11 router-go 改变
router-go
改变 问题的提示是:
文档见:
直接全局替换 router-go
为 router-push
3.12 track-by 替换
track-by
替换问题的提示是:
文档见:
直接代码全局替换 track-by
为 :key
3.13 router 路由定义的替换
router
替换的提示是:
文档见:
这个地方比较麻烦,要把所有路由定义都修改了。包括子路由的定义。原来的代码是:
import Vue from 'vue'import Router from 'vue-router'...Vue.use(Router)var router = new Router()router.map({ //定义路由映射 '/': { name: 'main', component: Main, subRoutes: { '/': { name: 'list', component: List }, '/list': { name: 'list', component: List } }, }, '/add/:assetId': { name: 'add', component: Add }});router.start(Assets, '#app')复制代码
修改为:
import Vue from 'vue'import VueRouter from 'vue-router'...Vue.use(VueRouter)var router = new VueRouter({ routes: [ { path: '/', name: 'main', component: Main, children: [ { path: '/', name: 'list', component: List }, { path: '/list', name: 'list', component: List } ] }, { path: '/add/:assetId', name: 'add', component: Add } ]})const vm = new Vue({ router, render: h => h(Assets)}).$mount('#app')复制代码
3.14 v-bind 的 once 和 sync 修饰符移除
v-bind
的 once
和 sync
修饰符移除问题提示是:
文档见:
这个问题将近 100 个地方,因为项目中定义了大量的组件。比如 翻页组件、日期组件、上传组件、地点组件等等。
在 Vue1.x 时可以增加 sync
修饰符实现父组件和子组件的双向绑定,但是到了 Vue2.x prop
只能单向传递,意思就是只能父组件以 prop
方式将数据传入子组件,但是子组件中不可以对 prop
中的值进行修改,即无法双向绑定。
如果想要通知父组件进行数据修改需要定义组件事件,然后子组件中使用 $emit(eventName)
触发事件,父组件中使用 $on(eventName)
监听事件。
这个问题改的比较多,消耗了很多的时间。首先我要把涉及的组件重新设计,改成反向事件触发修改父组件属性,然后父组件要监听修改函数。
4 编译项目
至此,基本上所有工具扫描出来的问题基本上改完了。但这还远远不够,当我 npm run dev
时又报出来很多错误。基本上总结以下几个问题。
4.1 template 下只能有一个根组件
问题报错:
原来是我的 vue 文件中的 template
节点下有多个 div
节点。不知道为什么 Vue1.x 没有报错。全部统一为一个 div
根节点。
4.2 delete 方法被占用
我的一些方法定义是 delete
,这时报错 delete
是 JavaScript 的关键字。我需要所有修改为另一个名称。
复制代码
4.3 重复的 :class 和 :click
这个可能是我在迁移的时候一个标签里有了重复的 :class
, :click
属性。自己删除或者整合一下就行
5 运行检查
编译通过后,终于可以跑起来了。这时候就需要每个页面进行测试,每个操作进行测试。发现了以下几个问题
- router.afterEach 方法有了修改,工具没有识别出来,手动查询做了修改文档可以参见 和 识别前后版本的区别。
- Vue.$set 方法已经废弃但是未被识别,手动查询做了修改
- 2.x 中增加了 HTML 保留关键字,之前我定义的
content
address
组件都不能叫做这个名字了。要么首字母改成大写。要么换个名字。详细可见:
所有页面跑过一遍,很多小细节慢慢调试修改,一定要细心再细心。(改的最多的还是组件的部分)
结尾
最后500多个问题总共耗时2天多的时间才完全跑通原有的项目。不过升级到 Vue2.x 后首先做的就是引入了饿了么组件,感觉方便很多,还有一些其他插件在升级后都可以方便的使用。
注:以上只是我升级迁移过程遇到的问题。每个项目不同会有不同的问题,建议以官方迁移文档为主。
更多文章关注我的公众号