Vue 2.0 升(cai)級(keng)之旅

Troubleshooting of upgrading Vue from 1.0 to 2.0

系列文章:

  1. Vue 2.0 升(cai)級(keng)之旅 (本文)
  2. Vuex — The core of Vue application

本文不包含 Vue 2.0 所有新特性悉尾,如 SSR 等,本文并沒有涉及挫酿,本文只包含個人博客項目升級中所遇到的經(jīng)驗分享构眯,如有興趣,可以查看 Vue 2.0 changes log早龟。

前言

這節(jié)凈是些嘮叨鸵赖,只想看升(tian)級(keng)的可直接跳過。

從去年年底開始寫博客拄衰,那時對怎么搞個博客網(wǎng)站一竅不通,看別人用 Github Pages 寫博客挺贊的饵骨,就也想搞個玩玩翘悉。技術(shù)選型時,在 jekyllhexo 中選擇了前者居触,或許你會問為什么妖混?估計當(dāng)時大腦的供氧量不足了吧...

于是,我的博客就這么誕生了轮洋。(jekyll 版的博客已經(jīng)廢棄了制市,如果你有興趣领追,可以查看之前的提交

可是雌澄,用久了就發(fā)現(xiàn)并不怎么好用黑忱,雖然支持 markdown,可代碼塊要轉(zhuǎn)換成 highlighter 標(biāo)簽肢预;其次,主題模板是挺好看悉患,可換成中文字雜就那么別扭哪肩钠;還有,對 jekyll 的模板又不熟兽间,自定義也不方便历葛。

年初有一天,突然想到自己也是搞技術(shù)的嘀略,為啥不自己搭一個博客網(wǎng)站哪恤溶?對,順帶還能學(xué)學(xué)新技術(shù)帜羊,何樂而不為咒程。又到了技術(shù)選型的時候了,這次擺在我面前又有 2 個選擇逮壁,ReactVue孵坚,這次我選擇了后者。

Why窥淆?因為卖宠,后者更輕量級,也更貼近我熟悉的 Angular 的語法忧饭,還有扛伍,那時網(wǎng)上就有說今年 4 月 Vue 會升級到 2.0 和 Vue 兼具 React 和 Angular 的優(yōu)點等等。(好吧词裤,老實說刺洒,不選 React 只是因為不喜歡 JSX 而已。-_-||)

So吼砂,我就用 Vue 1.10+ 搭建了自己的新博客——Disciple.Ding Blog(點這里看源碼)逆航,并漸漸地往里添加一些新學(xué)到的東西,ES6, webpack, docker 等渔肩,并在 DAOcloud 上發(fā)布了因俐。(免費用了人家那么久的服務(wù),在這里做個硬廣也是應(yīng)該的周偎,DAOcloud 的確很好用抹剩,特別和 Github 綁定之后能自動構(gòu)建,應(yīng)用更新也及其簡單蓉坎,只是有個缺點就是有帶寬限制澳眷。)

在不久之前,Vue 如約發(fā)布了 2.0 版本蛉艾。正如計劃之初钳踊,博客 Vue 的版本也將升級到 2.0衷敌。

說了那么多,再不進入正題就要變成標(biāo)題黨了箍土。好逢享,那就開始我們的升(cai)級(keng)之旅。

升(tian)級(keng)之旅

首先吴藻,升級依賴瞒爬。

npm install vue@next vue-router@next --save

import vue

順利安裝完成并按 changelog 做了修改之后,啟動項目也正常沟堡,當(dāng)我興致勃勃地打開 Browser侧但,駕輕就熟地輸入 localhost,并自然而然地按下 Enter航罗,一切水到渠成禀横。

然而,迎接我的竟是一片白板粥血,控制臺里赫然映著一串紅字柏锄。

[Vue warn]: You are using the runtime-only build of Vue where the template option is not available. Either pre-compile the templates into render functions, or use the compiler-included build. (found in root instance)

What? template 選項不能用了,changelog 沒提到案纯鳌趾娃?但 vue-router 的例子中都在用啊,什么鬼缔御?甚至我將代碼全部替換成例子中的代碼依舊無法運行抬闷,但在 vue-router 項目里就能跑,什么鬼案弧笤成!

但是,我并不妥協(xié)眷茁,分別打斷點運行炕泳,發(fā)現(xiàn)兩者竟然跑的不是同一段代碼,納尼上祈!

import vue from 'vue'

同樣的 import 語句喊崖,卻有不一樣的結(jié)果,vue-router 中引的是 vue.js雇逞,而在我的項目中引的竟然是 vue.common.js...common...mon...n...

vue.common.js...common...mon...n...

為什么會引 vue.common.js,from 'vue' 不該引的是 vue.js 么茁裙?這就要引入另一個知識點:package.json塘砸。

package.json 中的 main 屬性決定了,當(dāng)項目被引入時晤锥,輸出的是哪個文件掉蔬,而 vue 的 package.json 中的 main 指向的是 dist/vue.common.js廊宪。

福利時間:推薦一個網(wǎng)站 json.is,它對 package.json 里的每條屬性都有詳細的解釋女轿。

找到了問題產(chǎn)生的原因箭启,那么解決也就輕而易舉了。

import vue from 'vue/dist/vue.js'

每次引用 vue 的時候都要寫那么長蛉迹,一點都不優(yōu)雅傅寡,而且為什么 vue-router 的例子可以用啊北救?

我要一探究竟荐操。確認了 vue-router 中依賴的 vue 的 package.json 文件中的 main 字段指向的也是 dist/vue.common.js。那就只有一個可能了珍策,webpack 對引入做了處理托启,查看 webpack.config.js

module.exports = {
    // 省略...
    resolve: {
        alias: {
            'vue': 'vue/dist/vue.js'
        }
    },
    ...

果然啊~他用 webpack 的別名功能把 vue/dist/vue.js 命名成了 vue,防不勝防攘宙。

在自己項目的 wepack.config.js 里同樣給 vue 起別名屯耸,這樣就又能愉快地使用 import vue from 'vue' 了。

你是不是以為這樣就結(jié)束了蹭劈?不疗绣,對待一個問題要刨根問底,不能不求甚解链方。

為什么 vue 默認導(dǎo)出的是 vue.common.js持痰,它和 vue.js 的區(qū)別在哪里,又有什么關(guān)系祟蚀?

這個問題在囧克斯的博客中有提到工窍。

Vue 最早會打包生成三個文件,一個是 runtime only 的文件 vue.common.js前酿,一個是 compiler only 的文件 compiler.js患雏,一個是 runtime + compiler 的文件 vue.js。

也就是說罢维,vue.js = vue.common.js + compiler.js淹仑,而如果要使用 template 這個屬性的話就一定要用 compiler.js,那么肺孵,引入 vue.js 是最恰當(dāng)?shù)摹?/p>

第一句代碼就把我坑那么久匀借,后面還會有多少坑哪?

路由升級

vue-router 的升級并不困難平窘,參照 Releases Note 上的注釋修改應(yīng)該沒有什么大問題吓肋,主要的變化有兩點:

  1. 路由配置從一系列的方法調(diào)用,變成了傳遞一個配置對象
  2. 原先的 v-link 指令瑰艘,變成了 router-link Component是鬼,路徑指向用 to 屬性

正當(dāng)你以為會一路順風(fēng)順?biāo)粑瑁p松升級路由完成的時候,現(xiàn)實總會給你當(dāng)頭一棒均蜜。

之前博客的 vue-router 中使用了 beforeEachafterEach 方法李剖,根據(jù) Release Note

  • router.beforeEach (replaced by the beforeEach option)
  • router.afterEach (replaced by the afterEach option)

行,那我把它改到配置里

const ROUTER_SETTING = {
    routes: [
        // 省略...
    ],
    beforeEach: () => { /* some function */ },
    afterEach: () => { /* some function */ }
}

But, not work. What's wrong?

難道我哪里寫錯了囤耳?又經(jīng)過我一番谷哥和查閱文檔之后篙顺,發(fā)現(xiàn)在下一個版本的 Release Note 中有這么一段

  • beforeEach and afterEach are reverted as router instance methods (options removed). This makes it more convenient for plugins/modules to add hooks after the router instance has been created.

好吧,它又被恢復(fù)回路由實例的方法了紫皇。那么慰安,改回去

const router = new VueRouter(ROUTER_SETTING);

router
    .beforeEach(() => { /* some function */ })
    .afterEach(() => { /* some function */ });

OK,這樣總好了吧聪铺。然而化焕,并沒有...console 中報出無法從 undefined 中讀取 afterEach,好吧铃剔,我猜這應(yīng)該是 beforeEach 中沒有像之前一樣返回路由對象撒桨,所以不能鏈式調(diào)用。

class VueRouter {
    // 省略...
    beforeEach (fn: Function) {
        this.beforeHooks.push(fn)
    }
    
    afterEach (fn: Function) {
        this.afterHooks.push(fn)
    }
    // 省略...
}

看一眼源碼键兜,果然如此凤类。

那再將之前的代碼稍作修改就可以了。

const router = new VueRouter(ROUTER_SETTING);

router.beforeEach(() => { /* some function */ });
router.afterEach(() => { /* some function */ });

不過普气,不能鏈式調(diào)用似乎沒之前的優(yōu)雅了哪~

最后谜疤,提一下 vue-router 2.0 里所有的 hook(就像之前的 beforeEach, afterEach,以及每個路由狀態(tài)中的 beforeEnter, beforeRouteLeave等)都具有相同的參數(shù)簽名现诀,這在 Release Note 中也有提到夷磕。

fn (toRoute, redirect, next) {
    // toRoute: {Object} 當(dāng)前路由對象
    // redirect: {Function} 調(diào)用跳轉(zhuǎn)至另一路由
    // next: {Function} 調(diào)用繼續(xù)當(dāng)前路由跳轉(zhuǎn)
    // 什么都不做,則取消當(dāng)前跳轉(zhuǎn)
}

路由升級完成后仔沿,如果控制臺沒有什么報錯坐桩,那么,路由可以相互切換了封锉,那些不依賴數(shù)據(jù)讀取的組件已經(jīng)可以正常顯示了绵跷。

那些依賴數(shù)據(jù)讀取的組件哪?

這就要提到組件的生命周期鉤子(即 lifecycle hooks)成福。

Lifecycle hooks

生命周期鉤子應(yīng)該算 vue 這次升級中 broken changes 最多的一部分了碾局,對照 1.0 的文檔release note,作了下面這張表

vue 1.0+ vue 2.0 Description
init beforeCreate 組件實例剛被創(chuàng)建奴艾,組件屬性計算之前擦俐,如 data 屬性等
created created 組件實例創(chuàng)建完成,屬性已綁定握侧,但 DOM 還未生成蚯瞧,$el 屬性還不存在
beforeCompile beforeMount 模板編譯/掛載之前
compiled mounted 模板編譯/掛載之后
ready mounted 模板編譯/掛載之后(不保證組件已在 document 中)
- beforeUpdate 組件更新之前
- updated 組件更新之后
- activated for keep-alive,組件被激活時調(diào)用
- deactivated for keep-alive品擎,組件被移除時調(diào)用
attached - 不用了還說啥哪...
detached - 那就不說了吧...
beforeDestory beforeDestory 組件銷毀前調(diào)用
destoryed destoryed 組件銷毀后調(diào)用

知道了 hooks 升級前后的對應(yīng)關(guān)系埋合,那么升級起來就輕而易舉了,改改組件的屬性名就可以了萄传。

那么甚颂,改完屬性名是不是就完成了?然而并沒有秀菱。

因為振诬,在 vue 1.0+ 中,如果一個組件和路由相關(guān)衍菱,那么赶么,它就可能不單單有自己組件的 lifecycle hooks,它還會有基于 vue-router 的 lifecycle hooks脊串。

而在 vue 2.0 中辫呻,router lifecycle hooks 全部被移除了,因為琼锋,這些 hooks 可以通過其他的方式來代替放闺,這樣不但簡化了配置,還不用在組件中去處理路由相關(guān)的業(yè)務(wù)缕坎,降低了耦合怖侦。那這些 hooks 該如何替換,我們接下來就來看一下谜叹。

  • activate & deactivate:使用組件自身的 lifecycle hook 替代
  • data:通過組件 watch 屬性來監(jiān)聽當(dāng)前路由 $route 的變化
  • canActivate:由路由屬性 beforeEnter 來代替
  • canDeactivate:由路由屬性 beforeRouteLeave 來代替
  • canReuse:去除

那個這個是不是也直接改改屬性名就好了哪匾寝?

恩,差不多叉谜。不過需要注意的是旗吁,如果原先 hooks 中使用了有關(guān)路由信息的 transition 參數(shù)是肯定不能用了。比如停局,根據(jù)路由參數(shù)來進行查詢很钓,原先通過 transition.to.params 獲取路由參數(shù),現(xiàn)在就要通過剛剛提到的當(dāng)前路由對象 this.$route.params 來獲取董栽。

在升級這里的過程中码倦,還遇到一個問題:當(dāng)用戶輸入的 URL 滿足路由匹配,但根據(jù)路由參數(shù)無法獲得正確的文章時锭碳,我想讓路由直接跳轉(zhuǎn)到首頁袁稽。

在 1.0 版本中,我通過 transition.redirect('/'); 就輕松的回到了首頁擒抛,由于 2.0 中沒有 transition 參數(shù)推汽,而 $route 只包含當(dāng)前路由的信息补疑,并不包換路由切換的操作。那該怎么做哪歹撒?再一次谷哥和查閱文檔莲组,然而一無所獲。

i choose death

最后在 vue-router 的例子中找到了解決問題的鑰匙——$router暖夭。

$router 返回的是整個項目路由的實例锹杈,它是只讀的。于是迈着,剛剛那個問題就可以通過 this.$router.replace('/'); 來解決竭望。

這里還有一點,在 1.0 版本中組件配置 route 屬性時還可以設(shè)置一個叫 waitForData 的屬性裕菠。這個在 2.0 中咬清,我還沒有找到直接的替換方式,不過糕韧,我在整個組件上添加 v-if 來處理枫振。從理論和效果的角度上講,v-if 是可以替代原先的 waitForData 屬性萤彩,就似乎不那么優(yōu)雅粪滤。

剩余其他小點,看控制臺報錯信息雀扶,然后查查 Release Note 都能輕松處理啦~

至此杖小,我的整個 Blog 也升級完成了,歡迎來訪愚墓。(查看源碼戳這里

寫在最后

如果現(xiàn)在再讓我選一個技術(shù)來搭博客的話予权,我會選 React。為啥浪册?

因為 vue 我已經(jīng)玩過啦扫腺,哈哈哈~

最后,借用外國網(wǎng)友的一句話:

I'm constantly rewriting / refactoring this silly little blog using the latest and buzziest tech, so that I can stay up to date on these libraries and frameworks.

這也是我自己搭博客村象,而不是直接使用博客系統(tǒng)的主要原因笆环。

最后的最后,安利下自己的 Blog厚者,以及 Source Code躁劣。

歡迎交流,噴子繞道库菲。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末账忘,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌鳖擒,老刑警劉巖溉浙,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異蒋荚,居然都是意外死亡放航,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門圆裕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人荆几,你說我怎么就攤上這事吓妆。” “怎么了吨铸?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵行拢,是天一觀的道長。 經(jīng)常有香客問我诞吱,道長舟奠,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任房维,我火速辦了婚禮沼瘫,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘咙俩。我一直安慰自己耿戚,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布阿趁。 她就那樣靜靜地躺著膜蛔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪脖阵。 梳的紋絲不亂的頭發(fā)上皂股,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天,我揣著相機與錄音命黔,去河邊找鬼呜呐。 笑死,一個胖子當(dāng)著我的面吹牛纷铣,可吹牛的內(nèi)容都是我干的卵史。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼搜立,長吁一口氣:“原來是場噩夢啊……” “哼以躯!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤忧设,失蹤者是張志新(化名)和其女友劉穎刁标,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體址晕,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡膀懈,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了谨垃。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片启搂。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖刘陶,靈堂內(nèi)的尸體忽然破棺而出胳赌,到底是詐尸還是另有隱情,我是刑警寧澤匙隔,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布疑苫,位于F島的核電站,受9級特大地震影響纷责,放射性物質(zhì)發(fā)生泄漏捍掺。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一再膳、第九天 我趴在偏房一處隱蔽的房頂上張望挺勿。 院中可真熱鬧,春花似錦饵史、人聲如沸满钟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽湃番。三九已至,卻和暖如春吭露,著一層夾襖步出監(jiān)牢的瞬間吠撮,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工讲竿, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留泥兰,地道東北人。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓题禀,卻偏偏與公主長得像鞋诗,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子迈嘹,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容