Vue1.x 遷移 Vue2.x 實戰

Tsy遠發表於2019-03-02

本篇文章記錄了完整的前端 Vue1.x 專案遷移至 Vue2.x 的步驟和遇到的問題。並且在遷移的過程也對Vue進行進一步學習。

1 為什麼要遷移 Vue2.x

由於專案後面希望用到餓了麼的 vue 元件,而且當前很多元件都是基於 Vue2.x 的,對於 Vue1.x 都已經不再維護。

Vue2.x 更加成熟,並且後面準備在移動端接入 weex ,而 weex 中也推薦使用 Vue2.x 進行開發。

綜上所述,下定決心開始對 Vue1.x 的專案進行遷移。

2 前期準備

先介紹下原有專案的大致情況。

  1. 專案不是單純的單頁面應用,每個大模組是一個單頁面應用,大模組中的子模組的跳轉使用路由進行跳轉。
  2. 原有專案 vue 版本號1.0.21,vue-router 版本號0.7.13,未使用 vuex ,網路請求用的就是 jquery

希望在遷移後,新功能的新增可以完全使用單頁面應用,並且配合用上 vuex 和網路請求庫( axios )還有一些其他的外掛。

現附上在遷移過程中相關文件地址:

  1. Vue 官方遷移文件
    這也是遷移過程中主要的參考文件
  2. vue-migration-helper
    官方遷移的輔助工具,用以遍歷查詢出需要遷移的地方。識別出舊有的特性後,就會告知並給出建議,同時附上關於詳細資訊的連結。
  3. vue-router 2.x 官方文件
  4. 萬能的 Google

3 開始遷移

3.1 檢查出遷移的地方

先安裝官方遷移工具vue-migration-helper

npm install --global vue-migration-helper複製程式碼

安裝完成後進入專案目錄,掃描專案中檔案找出需要遷移的程式碼位置。(並不能完全找出,但是可以解決大部分的遷移)

我的遷移做法是掃描全域性後,專注修改一類遷移問題,修改完後commit並且再次掃描確認該類問題已經解決。然後再解決下一類的問題。

第一次掃描並輸出到檔案中

vue-migration-helper >a.log複製程式碼

輸出一看,WTF!!!500多個遷移點,網上人家遷移就幾十個遷移點。呵呵噠了。

Vue1.x 遷移 Vue2.x 實戰
第一次掃描結果

3.2 package.json修改

首先提示的是修改 package.json 中的版本號,並重新 npm install

Vue1.x 遷移 Vue2.x 實戰
package.json 修改

這個沒啥,我直接升到了最新的vue和vue-router版本

第一個解決的是 v-link 提示資訊如下

Vue1.x 遷移 Vue2.x 實戰
替換 v-link

找到相關文件 cn.vuejs.org/v2/guide/mi…

文件描述是把

<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 的移除問題的提示是這樣的

Vue1.x 遷移 Vue2.x 實戰
$index 和 $key 的移除

文件見 cn.vuejs.org/v2/guide/mi…

主要是 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 的計算插值移除 提示是這樣的

Vue1.x 遷移 Vue2.x 實戰
HTML 的計算插值移除

文件見 cn.vuejs.org/v2/guide/mi…

這個替換比較簡單,就是把 {{{}}} 全部替換為 v-html

3.6生命週期 ready 替換

生命週期 ready 替換 提示是這樣的

Vue1.x 遷移 Vue2.x 實戰
生命週期 ready 替換

要把生命週期鉤子函式 ready 替換為以下:

mounted: function () {
  this.$nextTick(function () {
    // 程式碼保證 this.$el 在 document 中
  })
}複製程式碼

在這裡我回頭看了下 nextTick 的具體概念:cn.vuejs.org/v2/guide/re…

意思就是當資料發生變化後 DOM 不會立即更新,而是會在一個更新週期時統一更新(感覺就像 Android 的16ms 渲染重新整理)。所以使用 nextTick,是一個非同步執行,意思是方法裡面的程式碼會在下次 DOM 更新後執行。

3.7 Array-prototype-$remove 移除

Array-prototype-$remove 移除問題的提示:

Vue1.x 遷移 Vue2.x 實戰
Array-prototype-$remove 移除

文件見 cn.vuejs.org/v2/guide/mi…

陣列的一個 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-elv-ref 替換問題的提示:

Vue1.x 遷移 Vue2.x 實戰
v-el 和 v-ref 替換

文件見:cn.vuejs.org/v2/guide/mi…

直接全域性將 v-elv-ref 換成 ref

3.9 屬性內部的計算插值移除 ({{ }})

屬性內部的計算插值移除的提示:

Vue1.x 遷移 Vue2.x 實戰
屬性內部的計算插值移除

文件見:cn.vuejs.org/v2/guide/mi…

屬性內部的計算插值已經不能再使用了:

<button class="btn btn-{{ size }}"></button>複製程式碼

應該寫成行內表示式:

<button v-bind:class="`btn btn-` + size"></button>複製程式碼

3.10 v-for 遍歷陣列/物件時的引數順序變更

v-for 遍歷陣列/物件時的引數順序變更問題的提示:

Vue1.x 遷移 Vue2.x 實戰
v-for 遍歷陣列/物件時的引數順序變更

文件見:cn.vuejs.org/v2/guide/mi…

當包含 index key 時,之前遍歷陣列時的引數順序是 (index, value) 。現在是 (value, index) , 目的為了和 Javascript 原生中的順序保持一致。

3.11 router-go 改變

router-go 改變 問題的提示是:

Vue1.x 遷移 Vue2.x 實戰
router-go 改變

文件見:cn.vuejs.org/v2/guide/mi…

直接全域性替換 router-gorouter-push

3.12 track-by 替換

track-by 替換問題的提示是:

Vue1.x 遷移 Vue2.x 實戰
track-by 替換

文件見:cn.vuejs.org/v2/guide/mi…

直接程式碼全域性替換 track-by:key

3.13 router 路由定義的替換

router 替換的提示是:

Vue1.x 遷移 Vue2.x 實戰
router 路由定義的替換

文件見:cn.vuejs.org/v2/guide/mi…

這個地方比較麻煩,要把所有路由定義都修改了。包括子路由的定義。原來的程式碼是:

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-bindoncesync 修飾符移除問題提示是:

Vue1.x 遷移 Vue2.x 實戰
v-bind 的 once 和 sync 修飾符移除

文件見:cn.vuejs.org/v2/guide/mi…

這個問題將近 100 個地方,因為專案中定義了大量的元件。比如 翻頁元件、日期元件、上傳元件、地點元件等等。

在 Vue1.x 時可以增加 sync 修飾符實現父元件和子元件的雙向繫結,但是到了 Vue2.x prop 只能單向傳遞,意思就是隻能父元件以 prop 方式將資料傳入子元件,但是子元件中不可以對 prop 中的值進行修改,即無法雙向繫結。

如果想要通知父元件進行資料修改需要定義元件事件,然後子元件中使用 $emit(eventName) 觸發事件,父元件中使用 $on(eventName) 監聽事件。

這個問題改的比較多,消耗了很多的時間。首先我要把涉及的元件重新設計,改成反向事件觸發修改父元件屬性,然後父元件要監聽修改函式。

4 編譯專案

至此,基本上所有工具掃描出來的問題基本上改完了。但這還遠遠不夠,當我 npm run dev 時又報出來很多錯誤。基本上總結以下幾個問題。

4.1 template 下只能有一個根元件

問題報錯:

Vue1.x 遷移 Vue2.x 實戰
template 下只能有一個根元件

原來是我的 vue 檔案中的 template 節點下有多個 div 節點。不知道為什麼 Vue1.x 沒有報錯。全部統一為一個 div 根節點。

4.2 delete 方法被佔用

Vue1.x 遷移 Vue2.x 實戰
Paste_Image.png

我的一些方法定義是 delete ,這時報錯 delete 是 JavaScript 的關鍵字。我需要所有修改為另一個名稱。

<modal title="系統提示" text="確定刪除嗎?" id="deleteModal" :confirm-action="delete"></modal>複製程式碼

4.3 重複的 :class 和 :click

這個可能是我在遷移的時候一個標籤裡有了重複的 :class , :click 屬性。自己刪除或者整合一下就行

5 執行檢查

編譯通過後,終於可以跑起來了。這時候就需要每個頁面進行測試,每個操作進行測試。發現了以下幾個問題

  1. router.afterEach 方法有了修改,工具沒有識別出來,手動查詢做了修改
    文件可以參見 github.com/vuejs/vue-r…router.vuejs.org/zh-cn/advan… 識別前後版本的區別。
  2. Vue.$set 方法已經廢棄但是未被識別,手動查詢做了修改
  3. 2.x 中增加了 HTML 保留關鍵字,之前我定義的 content address 元件都不能叫做這個名字了。要麼首字母改成大寫。要麼換個名字。
    詳細可見:jingsam.github.io/2016/10/30/…

所有頁面跑過一遍,很多小細節慢慢除錯修改,一定要細心再細心。(改的最多的還是元件的部分)

結尾

最後500多個問題總共耗時2天多的時間才完全跑通原有的專案。不過升級到 Vue2.x 後首先做的就是引入了餓了麼元件,感覺方便很多,還有一些其他外掛在升級後都可以方便的使用。

注:以上只是我升級遷移過程遇到的問題。每個專案不同會有不同的問題,建議以官方遷移文件為主。

更多文章關注我的公眾號

Vue1.x 遷移 Vue2.x 實戰
我的公眾號

相關文章