本篇文章記錄了完整的前端 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 )還有一些其他的插件。
現附上在遷移過程中相關文檔地址:
-
Vue 官方遷移文檔
這也是遷移過程中主要的參考文檔 -
vue-migration-helper
官方遷移的輔助工具,用以遍歷查找出需要遷移的地方。識別出舊有的特性后,就會告知并給出建議,同時附上關于詳細信息的鏈接。 - vue-router 2.x 官方文檔
- 萬能的 Google
3 開始遷移
3.1 檢查出遷移的地方
先安裝官方遷移工具vue-migration-helper
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
提示信息如下
找到相關文檔 https://cn.vuejs.org/v2/guide/migration-vue-router.html#v-link-替換
文檔描述是把
<a v-link="'/about'">About</a>
替換成
<router-link to="/about">About</router-link>
But,項目中是這么寫的
<button class="btn btn-default pull-right" v-link="{ path: '/'}">返回</button>
查詢最新的 vue-router 文檔,可以使用編程式導航,改成如下
<button class="btn btn-default pull-right" @click="$router.push({ path: '/'})">返回</button>
然后查找所有 v-link
類型問題一個個全部改過來,commit 提交。重新掃描一次。
3.4 $index 和 $key 的移除
$index
和 $key
的移除問題的提示是這樣的
文檔見 https://cn.vuejs.org/v2/guide/migration.html#index-and-key-移除
主要是 Vue2.x 中移除了隱變量 $index
和 $key
,全部顯示聲明。修改例子如下
<tr v-for="clinic of clinicDatas">
<td>{{ $index+1 }}</td>
</tr>
改為:
<tr v-for="(clinic, index) of clinicDatas">
<td>{{ index+1 }}</td>
</tr>
回頭重新看了下 v-for
的文檔
默認命名 index
代表索引,key
代表遍歷對象的鍵值。
比如遍歷一個數組的時候,第二個參數是 index
索引
<ul id="example-2">
<li v-for="(item, index) in items">
{{ parentMessage }} - {{ index }} - {{ item.message }}
</li>
</ul>
當遍歷對象時,第二個參數是 key
鍵
<div v-for="(value, key) in object">
{{ key }} : {{ value }}
</div>
同時如果遍歷對象,還可以有第三個參數代表索引
<div v-for="(value, key, index) in object">
{{ index }}. {{ key }} : {{ value }}
</div>
3.5 HTML 的計算插值移除 ({{{ }}})
HTML 的計算插值移除 提示是這樣的
文檔見 https://cn.vuejs.org/v2/guide/migration.html#HTML-計算插值-移除
這個替換比較簡單,就是把 {{{}}}
全部替換為 v-html
3.6生命周期 ready 替換
生命周期 ready 替換 提示是這樣的
要把生命周期鉤子函數 ready
替換為以下:
mounted: function () {
this.$nextTick(function () {
// 代碼保證 this.$el 在 document 中
})
}
在這里我回頭看了下 nextTick
的具體概念:https://cn.vuejs.org/v2/guide/reactivity.html#異步更新隊列
意思就是當數據發生變化后 DOM 不會立即更新,而是會在一個更新周期時統一更新(感覺就像 Android 的16ms 渲染刷新)。所以使用 nextTick
,是一個異步執行,意思是方法里面的代碼會在下次 DOM 更新后執行。
3.7 Array-prototype-$remove 移除
Array-prototype-$remove 移除問題的提示:
文檔見 https://cn.vuejs.org/v2/guide/migration.html#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
替換問題的提示:
文檔見:https://cn.vuejs.org/v2/guide/migration.html#v-el-和v-ref-替換
直接全局將 v-el
和 v-ref
換成 ref
3.9 屬性內部的計算插值移除 ({{ }})
屬性內部的計算插值移除的提示:
文檔見:https://cn.vuejs.org/v2/guide/migration.html#屬性內部的計算插值-移除
屬性內部的計算插值已經不能再使用了:
<button class="btn btn-{{ size }}"></button>
應該寫成行內表達式:
<button v-bind:class="'btn btn-' + size"></button>
3.10 v-for 遍歷數組/對象時的參數順序變更
v-for
遍歷數組/對象時的參數順序變更問題的提示:
文檔見:https://cn.vuejs.org/v2/guide/migration.html#v-for-遍歷數組時的參數順序-變更
當包含 index
key
時,之前遍歷數組時的參數順序是 (index, value)
?,F在是 (value, index)
, 目的為了和 Javascript 原生中的順序保持一致。
3.11 router-go 改變
router-go
改變 問題的提示是:
文檔見:https://cn.vuejs.org/v2/guide/migration-vue-router.html#router-go-改變
直接全局替換 router-go
為 router-push
3.12 track-by 替換
track-by
替換問題的提示是:
文檔見:https://cn.vuejs.org/v2/guide/migration.html#track-by-替換
直接代碼全局替換 track-by
為 :key
3.13 router 路由定義的替換
router
替換的提示是:
文檔見:https://cn.vuejs.org/v2/guide/migration-vue-router.html#router-map-替換
這個地方比較麻煩,要把所有路由定義都修改了。包括子路由的定義。原來的代碼是:
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
修飾符移除問題提示是:
文檔見:https://cn.vuejs.org/v2/guide/migration.html#v-bind-的-once和-sync-修飾符-移除
這個問題將近 100 個地方,因為項目中定義了大量的組件。比如 翻頁組件、日期組件、上傳組件、地點組件等等。
在 Vue1.x 時可以增加 sync
修飾符實現父組件和子組件的雙向綁定,但是到了 Vue2.x prop
只能單向傳遞,意思就是只能父組件以 prop
方式將數據傳入子組件,但是子組件中不可以對 prop
中的值進行修改,即無法雙向綁定。
如果想要通知父組件進行數據修改需要定義組件事件,然后子組件中使用 $emit(eventName)
觸發事件,父組件中使用 $on(eventName)
監聽事件。
這個問題改的比較多,消耗了很多的時間。首先我要把涉及的組件重新設計,改成反向事件觸發修改父組件屬性,然后父組件要監聽修改函數。
4 編譯項目
至此,基本上所有工具掃描出來的問題基本上改完了。但這還遠遠不夠,當我 npm run dev
時又報出來很多錯誤?;旧峡偨Y以下幾個問題。
4.1 template 下只能有一個根組件
問題報錯:
原來是我的 vue 文件中的 template
節點下有多個 div
節點。不知道為什么 Vue1.x 沒有報錯。全部統一為一個 div
根節點。
4.2 delete 方法被占用
我的一些方法定義是 delete
,這時報錯 delete
是 JavaScript 的關鍵字。我需要所有修改為另一個名稱。
<modal title="系統提示" text="確定刪除嗎?" id="deleteModal" :confirm-action="delete"></modal>
4.3 重復的 :class 和 :click
這個可能是我在遷移的時候一個標簽里有了重復的 :class
, :click
屬性。自己刪除或者整合一下就行
5 運行檢查
編譯通過后,終于可以跑起來了。這時候就需要每個頁面進行測試,每個操作進行測試。發現了以下幾個問題
- router.afterEach 方法有了修改,工具沒有識別出來,手動查詢做了修改
文檔可以參見 https://github.com/vuejs/vue-router/blob/1.0/docs/zh-cn/api/after-each.md 和 http://router.vuejs.org/zh-cn/advanced/navigation-guards.html 識別前后版本的區別。 - Vue.$set 方法已經廢棄但是未被識別,手動查詢做了修改
- 2.x 中增加了 HTML 保留關鍵字,之前我定義的
content
address
組件都不能叫做這個名字了。要么首字母改成大寫。要么換個名字。
詳細可見:https://jingsam.github.io/2016/10/30/vue-components-naming.html
所有頁面跑過一遍,很多小細節慢慢調試修改,一定要細心再細心。(改的最多的還是組件的部分)
結尾
最后500多個問題總共耗時2天多的時間才完全跑通原有的項目。不過升級到 Vue2.x 后首先做的就是引入了餓了么組件,感覺方便很多,還有一些其他插件在升級后都可以方便的使用。
注:以上只是我升級遷移過程遇到的問題。每個項目不同會有不同的問題,建議以官方遷移文檔為主。