從 Vue 1.x 遷移
從 Vue 1.x 遷移
目錄
FAQ
哇,非常長的一頁!是否意味著 Vue 2.0 已經(jīng)完全不同了呢,是否需要從頭學起呢,Vue 1.0 的項目是不是沒法遷移了?
非常開心地告訴你,并不是!幾乎 90% 的 API 和核心概念都沒有變。因為本節(jié)包含了很多詳盡的闡述以及許多遷移的例子,所以顯得有點長。不用擔心,你不必從頭到尾把本節(jié)讀一遍!
我該從哪里開始項目遷移呢?
1. 首先,在當前項目下運行遷移工具。我們非常謹慎地把高級 Vue 升級過程簡化為使用一個簡單的命令行工具。當工具識別出舊有的特性后,就會告知你并給出建議,同時附上關于詳細信息的鏈接。
2. 然后,瀏覽本頁面的側邊欄列出的內容。如果發(fā)現(xiàn)有的標題對你的項目有影響,但是遷移工具沒有給出提示,請檢查自己的項目。
3. 如果你的項目有測試代碼,運行并查看仍然失敗的地方。如果沒有測試代碼,在瀏覽器中打開你的程序,通過導航環(huán)顧并留意那些報錯或警告信息。
4. 現(xiàn)在,你的應用程序應該已徹底完成遷移。如果你渴望了解更多,可以閱讀本頁面剩余部分 - 或者從介紹部分,從頭開始深入新的文檔和改進過的指南。由于你已經(jīng)熟悉一些核心概念,所以許多部分已經(jīng)被刪除掉。
將 Vue 1.x 版本的應用程序遷移到 2.0 要花多長時間?
這取決于幾個因素:
取決于你應用程序的規(guī)模 (中小型的基本上一天內就可以搞定)。
取決于你分心和開始 2.0 最酷的新功能的次數(shù)。
無法判斷時間,我們構建 2.0 應用的時候也經(jīng)常發(fā)生這種事!
取決于你使用了哪些舊有的特性。大部分可以通過查找和替換 (find-and-replace) 來實現(xiàn)升級,但有一些可能還是要花點時間。如果你沒有遵循最佳實踐,Vue 2.0 會盡力強迫你去遵循。這有利于項目的長期運行,但也可能意味著重大重構 (盡管有些需要重構的部分可能已經(jīng)過時)。
如果我升級到到 Vue 2 ,我還必須同時升級 Vuex 和 Vue Router?
只有 Vue Router 2 與 Vue 2 保持兼容,所以 Vue Router 是需要升級的,你必須遵循 Vue Router 遷移方式來處理。幸運的是,大多數(shù)應用沒有很多 router 相關代碼,所以遷移可能不會超過一個小時。
對于 Vuex ,版本 0.8+ 與 Vue 2 保持兼容,所以部分不必強制升級??梢源偈鼓懔⒓瓷壍奈ㄒ焕碛桑悄阆胍褂媚切?Vuex 2 中新的高級特性,比如模塊 (modules) 和減少的樣板文件 (reduced boilerplate)。
模板
片段實例 移除
每個組件必須只有一個根元素。不再允許片段實例,如果你有這樣的模板:
<p>foo</p> <p>bar</p>
最好把整個內容都簡單包裹到一個新的元素里,如下所示:
<div> <p>foo</p> <p>bar</p> </div>
升級方式
升級后運行端到端測試套件 (end-to-end test suite) 或運行應用程序,并查看控制臺警告 (console warnings) 來找出那些模板中有多個根元素的地方。
生命周期鉤子函數(shù)
beforeCompile
移除
使用 created
鉤子函數(shù)替代。
升級方式
在代碼庫中運行遷移工具來找出所有使用此鉤子函數(shù)的示例。
compiled
替換
使用 mounted
鉤子函數(shù)替代。
升級方式
在代碼庫中運行遷移工具來找出所有使用此鉤子函數(shù)的示例。
attached
移除
使用其他鉤子函數(shù)內置的 DOM 檢測 (DOM check) 方法。例如,替換如下:
attached: function () { doSomething() }
可以這樣使用:
mounted: function () { this.$nextTick(function () { doSomething() }) }
升級方式
在代碼庫中運行遷移工具來找出所有使用此鉤子函數(shù)的示例。
detached
移除
使用其他鉤子函數(shù)內的 DOM 檢測 (DOM check) 方法。例如,替換如下:
detached: function () { doSomething() }
可以這樣使用:
destroyed: function () { this.$nextTick(function () { doSomething() }) }
升級方式
在代碼庫中運行遷移工具來找出所有使用此鉤子函數(shù)的示例。
init
重新命名
使用新的 beforeCreate
鉤子函數(shù)替代,本質上 beforeCreate 和 init 完全相同。init 被重新命名是為了和其他的生命周期方法的命名方式保持一致。
升級方式
在代碼庫中運行遷移工具來找出所有使用此鉤子函數(shù)的示例。
ready
替換
使用新的 mounted
鉤子函數(shù)替代。應該注意的是,使用 mounted
并不能保證鉤子函數(shù)中的 this.$el 在 document 中。為此還應該引入 Vue.nextTick
/vm.$nextTick
。例如:
mounted: function () { this.$nextTick(function () { // 代碼保證 this.$el 在 document 中 }) }
升級方式
在代碼庫中運行遷移工具來找出所有使用此鉤子函數(shù)的示例。
v-for
v-for
遍歷數(shù)組時的參數(shù)順序 變更
當包含 index
時,之前遍歷數(shù)組時的參數(shù)順序是 (index, value)
。現(xiàn)在是 (value, index)
,來和 JavaScript 的原生數(shù)組方法 (例如 forEach
和 map
) 保持一致。
升級方式
在代碼庫中運行遷移工具來找出那些使用舊有參數(shù)順序的示例。注意,如果你將你的 index 參數(shù)命名為一些不通用的名字 (例如 position
或 num
),遷移工具將不會把它們標記出來。
v-for
遍歷對象時的參數(shù)順序 變更
當包含 property 名稱/key 時,之前遍歷對象的參數(shù)順序是 (name, value)
。現(xiàn)在是 (value, name)
,來和常見的對象迭代器 (例如 lodash) 保持一致。
升級方式
在代碼庫中運行遷移工具來找出那些使用舊有參數(shù)順序的示例。注意,如果你將你的 key 參數(shù)命名為一些不通用的名字 (例如 name
或 property
),遷移工具將不會把它們標記出來。
$index
and $key
移除
已經(jīng)移除了 $index
和 $key
這兩個隱式聲明變量,以便在 v-for
中顯式定義。這可以使沒有太多 Vue 開發(fā)經(jīng)驗的開發(fā)者更好地閱讀代碼,并且在處理嵌套循環(huán)時也能產(chǎn)生更清晰的行為。
升級方式
在代碼庫中運行遷移工具來找出使用這些移除變量的示例。如果你沒有找到,也可以在控制臺錯誤中查找 (例如 Uncaught ReferenceError: $index is not defined
)。
track-by
替換
track-by
已經(jīng)替換為 key
,它的工作方式與其他屬性一樣,沒有 v-bind
或者 :
前綴,它會被作為一個字符串處理。多數(shù)情況下,你需要使用具有完整表達式的動態(tài)綁定 (dynamic binding) 來替換靜態(tài)的 key。例如,替換:
<div v-for="item in items" track-by="id">
你現(xiàn)在應該寫為:
<div v-for="item in items" v-bind:key="item.id">
升級方式
在代碼庫中運行遷移工具來找出那些使用track-by
的示例。
v-for
范圍值 變更
之前,v-for="number in 10"
的 number
從 0 開始到 9 結束,現(xiàn)在從 1 開始,到 10 結束。
升級方式
在代碼庫中使用正則 /\w+ in \d+/
搜索。當出現(xiàn)在 v-for
中,請檢查是否受到影響。
Props
coerce
Prop 的參數(shù) 移除
如果需要檢查 prop 的值,創(chuàng)建一個內部的 computed 值,而不再在 props 內部去定義,例如:
props: { username: { type: String, coerce: function (value) { return value .toLowerCase() .replace(/\s+/, '-') } } }
現(xiàn)在應該寫為:
props: { username: String, }, computed: { normalizedUsername: function () { return this.username .toLowerCase() .replace(/\s+/, '-') } }
這樣有一些好處:
你可以對保持原始 prop 值的操作權限。
通過給予驗證后的值一個不同的命名,強制開發(fā)者使用顯式申明。
升級方式
運行遷移工具找出包含 coerce
選項的實例。
twoWay
Prop 的參數(shù) 移除
Props 現(xiàn)在只能單向傳遞。為了對父組件產(chǎn)生反向影響,子組件需要顯式地傳遞一個事件而不是依賴于隱式地雙向綁定。詳見:
自定義輸入組件 (使用組件事件)
升級方式
運行遷移工具,找出含有 twoWay
參數(shù)的實例。
v-bind
的 .once
和.sync
修飾符 移除
Props 現(xiàn)在只能單向傳遞。為了對父組件產(chǎn)生反向影響,子組件需要顯式地傳遞一個事件而不是依賴于隱式地雙向綁定。詳見:
自定義輸入組件 (使用組件事件)
升級方式
運行遷移工具找到使用 .once 和 .sync
修飾符的實例。
修改 Props 棄用
組件內修改 prop 是反模式 (不推薦的) 的。比如,先聲明一個 prop ,然后在組件中通過 this.myProp = 'someOtherValue'
改變 prop 的值。根據(jù)渲染機制,當父組件重新渲染時,子組件的內部 prop 值也將被覆蓋。
大多數(shù)情況下,改變 prop 值可以用以下選項替代:
通過 data 屬性,用 prop 去設置一個 data 屬性的默認值。
通過 computed 屬性。
升級方式
運行端對端測試,查看關于 prop 修改的控制臺警告信息。
根實例的 Props 替換
對于一個根實例來說 (比如:用 new Vue({ ... })
創(chuàng)建的實例),只能用 propsData
而不是 props
。
升級方式
運行端對端測試,將會彈出 failed tests 來通知你使用 props
的根實例已經(jīng)失效。
計算屬性
cache: false
棄用
在 Vue 未來的大版本中,計算屬性的緩存驗證將會被移除。把不緩存的計算屬性轉換為方法可以得到和之前相同的結果。
示例:
template: '<p>message: {{ timeMessage }}</p>', computed: { timeMessage: { cache: false, get: function () { return Date.now() + this.message } } }
或者使用組件方法:
template: '<p>message: {{ getTimeMessage() }}</p>', methods: { getTimeMessage: function () { return Date.now() + this.message } }
升級方式
運行遷移工具找到 cache: false
的選項。
Built-In 指令
v-bind
真/假值 變更
在2.0中使用 v-bind
時,只有 null
, undefined
,和 false
被看作是假。這意味著,0
和空字符串將被作為真值渲染。比如 v-bind:draggable="''"
將被渲染為 draggable="true"
。
對于枚舉屬性,除了以上假值之外,字符串 "false"
也會被渲染為 attr="false"
。
注意,對于其它鉤子函數(shù) (如
v-if
和v-show
),他們依然遵循 js 對真假值判斷的一般規(guī)則。
升級方式
運行端到端測試,如果你 app 的任何部分有可能被這個升級影響到,將會彈出failed tests
用 v-on
監(jiān)聽原生事件 變更
現(xiàn)在在組件上使用 v-on
只會監(jiān)聽自定義事件 (組件用 $emit
觸發(fā)的事件)。如果要監(jiān)聽根元素的原生事件,可以使用 .native
修飾符,比如:
<my-component v-on:click.native="doSomething"></my-component>
升級方式
在代碼庫中運行遷移工具來找出所有使用此鉤子函數(shù)的示例。
帶有 debounce
的 v-model
移除
Debouncing 曾經(jīng)被用來控制 Ajax 請求及其它高耗任務的頻率。Vue 中v-model
的 debounce
屬性參數(shù)使得在一些簡單情況下非常容易實現(xiàn)這種控制。但實際上,這是控制了狀態(tài)更新的頻率,而不是控制高耗時任務本身。這是個微小的差別,但是會隨著應用增長而顯現(xiàn)出局限性。
例如在設計一個搜索提示時的局限性:
使用 debounce
參數(shù),便無法觀察 “Typing” 的狀態(tài)。因為無法對輸入狀態(tài)進行實時檢測。然而,通過將 debounce
與 Vue 解耦,可以僅僅只延遲我們想要控制的操作,從而避開這些局限性:
<!-- 通過使用 lodash 或者其它庫的 debounce 函數(shù), 我們相信 debounce 實現(xiàn)是一流的, 并且可以隨處使用它,不僅僅是在模板中。 --> <script src="https://cdn.jsdelivr.net/lodash/4.13.1/lodash.js"></script> <div id="debounce-search-demo"> <input v-model="searchQuery" placeholder="Type something"> <strong>{{ searchIndicator }}</strong> </div>
new Vue({ el: '#debounce-search-demo', data: { searchQuery: '', searchQueryIsDirty: false, isCalculating: false }, computed: { searchIndicator: function () { if (this.isCalculating) { return '? Fetching new results' } else if (this.searchQueryIsDirty) { return '... Typing' } else { return '? Done' } } }, watch: { searchQuery: function () { this.searchQueryIsDirty = true this.expensiveOperation() } }, methods: { // 這是 debounce 實現(xiàn)的地方。 expensiveOperation: _.debounce(function () { this.isCalculating = true setTimeout(function () { this.isCalculating = false this.searchQueryIsDirty = false }.bind(this), 1000) }, 500) } })
這種方式的另外一個優(yōu)點是:當包裹函數(shù)執(zhí)行時間與延時時間相當時,將會等待較長時間。比如,當給出搜索建議時,要等待用戶輸入停止一段時間后才給出建議,這個體驗非常差。其實,這時候更適合用 throttling 函數(shù)。因為現(xiàn)在你可以自由的使用類似 lodash 之類的庫,所以很快就可以用 throttling 重構項目。
Upgrade Path
運行遷移工具使用 debounce
參數(shù)的 實例。
使用 lazy
或者 number
參數(shù)的 v-model
。替換
lazy
和 number
參數(shù)現(xiàn)在以修飾符的形式使用,這樣看起來更加清晰,而不是這樣:
<input v-model="name" lazy> <input v-model="age" type="number" number>
現(xiàn)在寫成這樣:
<input v-model.lazy="name"> <input v-model.number="age" type="number">
升級方式
運行遷移工具找到這些棄用參數(shù)。
使用內聯(lián) value
的v-model
移除
v-model
不再以內聯(lián) value
方式初始化的初值了,顯然他將以實例的 data 相應的屬性作為真正的初值。
這意味著以下元素:
<input v-model="text" value="foo">
在 data 選項中有下面寫法的:
data: { text: 'bar' }
將渲染 model 為 ‘bar’ 而不是 ‘foo’ 。同樣,對 <textarea>
已有的值來說:
<textarea v-model="text"> hello world </textarea>
必須保證 text
初值為 “hello world”
升級方式
升級后運行端對端測試,注意關于v-model
內聯(lián)參數(shù)的 console warnings
v-model
with v-for
Iterated Primitive Values 移除
像這樣的寫法將失效:
<input v-for="str in strings" v-model="str">
因為 <input>
將被編譯成類似下面的 js 代碼:
strings.map(function (str) { return createElement('input', ...) })
這樣,v-model
的雙向綁定在這里就失效了。把 str
賦值給迭代器里的另一個值也沒有用,因為它僅僅是函數(shù)內部的一個變量。
替代方案是,你可以使用對象數(shù)組,這樣v-model
就可以同步更新對象里面的字段了,例如:
<input v-for="obj in objects" v-model="obj.str">
升級方式
運行測試,如果你的 app 有地方被這個更新影響到的話將會彈出failed tests提示。
帶有 !important
的 v-bind:style
移除
這樣寫將失效:
<p v-bind:style="{ color: myColor + ' !important' }">hello</p>
如果確實需要覆蓋其它的 !important
,最好用字符串形式去寫:
<p v-bind:style="'color: ' + myColor + ' !important'">hello</p>
升級方式
運行 遷移幫助工具。找到含有 !important
的 style 綁定對象。
v-el
和 v-ref
替換
簡單起見,v-el
和 v-ref
合并為一個 ref
屬性了,可以在組件實例中通過 $refs
來調用。這意味著 v-el:my-element
將寫成這樣:ref="myElement"
,v-ref:my-component
變成了這樣:ref="myComponent"
。綁定在一般元素上時,ref
指 DOM 元素,綁定在組件上時,ref
為一組件實例。
因為 v-ref
不再是一個指令了而是一個特殊的屬性,它也可以被動態(tài)定義了。這樣在和 v-for
結合的時候是很有用的:
<p v-for="item in items" v-bind:ref="'item' + item.id"></p>
以前 v-el
/v-ref
和 v-for
一起使用將產(chǎn)生一個 DOM 數(shù)組或者組件數(shù)組,因為沒法給每個元素一個特定名字。現(xiàn)在你還仍然可以這樣做,給每個元素一個同樣的ref
:
<p v-for="item in items" ref="items"></p>
和 1.x 中不同,$refs
不是響應的,因為它們在渲染過程中注冊/更新。只有監(jiān)聽變化并重復渲染才能使它們響應。
另一方面,設計$refs
主要是提供給 js 程序訪問的,并不建議在模板中過度依賴使用它。因為這意味著在實例之外去訪問實例狀態(tài),違背了 Vue 數(shù)據(jù)驅動的思想。
升級方式
運行遷移工具找出實例中的 v-el
和 v-ref
。
v-show
后面使用v-else
移除
v-else
不能再跟在 v-show
后面使用。請在v-if
的否定分支中使用v-show
來替代。例如:
<p v-if="foo">Foo</p> <p v-else v-show="bar">Not foo, but bar</p>
現(xiàn)在應該寫出這樣:
<p v-if="foo">Foo</p> <p v-if="!foo && bar">Not foo, but bar</p>
升級方式
運行遷移工具找出實例中存在的 v-else
以及 v-show
。
自定義指令 簡化
在新版中,指令的使用范圍已經(jīng)大大減小了:現(xiàn)在指令僅僅被用于低級的 DOM 操作。大多數(shù)情況下,最好是使用組件作為代碼復用的抽象層。
顯要的改變有如下幾點:
指令不再擁有實例。意思是,在指令的鉤子函數(shù)中不再擁有實例的
this
。替代的是,你可以在參數(shù)中接受你需要的任何數(shù)據(jù)。如果確實需要,可以通過el
來訪問實例。類似
acceptStatement
,deep
,priority
等都已被棄用。為了替換雙向
指令,見 示例。現(xiàn)在有些鉤子的意義和以前不一樣了,并且多了兩個鉤子函數(shù)。
幸運的是,新鉤子更加簡單,更加容易掌握。詳見 自定義指令指南。
升級方式
運行遷移工具找出定義指令的地方。在 helper 工具會把這些地方標記出來,因為很有可能這些地方需要重構。
指令 .literal
修飾符 移除
.literal 修飾符已經(jīng)被移除,為了獲取一樣的功能,可以簡單地提供字符串修飾符作為值。
示例,如下更改:
<p v-my-directive.literal="foo bar baz"></p>
只是:
<p v-my-directive="'foo bar baz'"></p>
升級方式
運行遷移工具找出實例中使用 `.literal` 修飾符的地方。
過渡
transition
參數(shù) 替換
Vue 的過渡系統(tǒng)有了徹底的改變,現(xiàn)在通過使用 <transition>
和 <transition-group>
來包裹元素實現(xiàn)過渡效果,而不再使用 transition
屬性。詳見 Transitions guide。
升級方式
運行遷移工具找到使用 transition
屬性的地方。
可復用的過渡 Vue.transition
替換
在新的過渡系統(tǒng)中,可以通過模板復用過渡效果。
升級方式
運行遷移工具找到使用 transition
屬性的地方。
過渡的 stagger
參數(shù) 移除
如果希望在列表渲染中使用漸近過渡,可以通過設置元素的 data-index
(或類似屬性) 來控制時間。請參考這個例子。
升級方式
運行遷移工具找到使用 transition
屬性的地方。升級期間,你可以“過渡”到新的過渡策略。
事件
events
選項 移除
events
選項被棄用。事件處理器現(xiàn)在在 created
鉤子中被注冊。參考詳細示例 $dispatch
and $broadcast
遷移指南
Vue.directive('on').keyCodes
替換
新的簡明配置 keyCodes
的方式是通過 Vue.config.keyCodes
例如:
// v-on:keyup.f1 不可用 Vue.config.keyCodes.f1 = 112
升級方式
運行遷移工具找到過時的 keyCode
配置
$dispatch
和 $broadcast
替換
$dispatch
和 $broadcast
已經(jīng)被棄用。請使用更多簡明清晰的組件間通信和更好的狀態(tài)管理方案,如:Vuex。
因為基于組件樹結構的事件流方式實在是讓人難以理解,并且在組件結構擴展的過程中會變得越來越脆弱。這種事件方式確實不太好,我們也不希望在以后讓開發(fā)者們太痛苦。并且$dispatch
和 $broadcast
也沒有解決兄弟組件間的通信問題。
對于$dispatch
和 $broadcast
最簡單的升級方式就是:通過使用事件中心,允許組件自由交流,無論組件處于組件樹的哪一層。由于 Vue 實例實現(xiàn)了一個事件分發(fā)接口,你可以通過實例化一個空的 Vue 實例來實現(xiàn)這個目的。
這些方法的最常見用途之一是父子組件的相互通信。在這些情況下,你可以使用 v-on
監(jiān)聽子組件上 $emit 的變化。這可以允許你很方便的添加事件顯性。
然而,如果是跨多層父子組件通信的話,$emit
并沒有什么用。相反,用集中式的事件中間件可以做到簡單的升級。這會讓組件之間的通信非常順利,即使是兄弟組件。因為 Vue 通過事件發(fā)射器接口執(zhí)行實例,實際上你可以使用一個空的 Vue 實例。
比如,假設我們有個 todo 的應用結構如下:
Todos ├─ NewTodoInput └─ Todo └─ DeleteTodoButton
可以通過單獨的事件中心管理組件間的通信:
// 將在各處使用該事件中心 // 組件通過它來通信 var eventHub = new Vue()
然后在組件中,可以使用 $emit
, $on
, $off
分別來分發(fā)、監(jiān)聽、取消監(jiān)聽事件:
// NewTodoInput // ... methods: { addTodo: function () { eventHub.$emit('add-todo', { text: this.newTodoText }) this.newTodoText = '' } }
// DeleteTodoButton // ... methods: { deleteTodo: function (id) { eventHub.$emit('delete-todo', id) } }
// Todos // ... created: function () { eventHub.$on('add-todo', this.addTodo) eventHub.$on('delete-todo', this.deleteTodo) }, // 最好在組件銷毀前 // 清除事件監(jiān)聽 beforeDestroy: function () { eventHub.$off('add-todo', this.addTodo) eventHub.$off('delete-todo', this.deleteTodo) }, methods: { addTodo: function (newTodo) { this.todos.push(newTodo) }, deleteTodo: function (todoId) { this.todos = this.todos.filter(function (todo) { return todo.id !== todoId }) } }
在簡單的情況下這樣做可以替代 $dispatch
和 $broadcast
,但是對于大多數(shù)復雜情況,更推薦使用一個專用的狀態(tài)管理層如:Vuex。
升級方式
運行遷移工具找出使用 $dispatch
和 $broadcast
的實例。
過濾器
插入文本之外的過濾器 移除
現(xiàn)在過濾器只能用在插入文本中 ({{ }}
tags)。我們發(fā)現(xiàn)在指令 (如:v-model
,v-on
等) 中使用過濾器使事情變得更復雜。像 v-for
這樣的列表過濾器最好把處理邏輯作為一個計算屬性放在 js 里面,這樣就可以在整個模板中復用。
總之,能在原生 js 中實現(xiàn)的東西,我們盡量避免引入一個新的符號去重復處理同樣的問題。下面是如何替換 Vue 內置過濾器:
替換 debounce
過濾器
不再這樣寫
<input v-on:keyup="doStuff | debounce 500">
methods: { doStuff: function () { // ... } }
請使用 lodash’s debounce
(也有可能是 throttle
) 來直接控制高耗任務??梢赃@樣來實現(xiàn)上面的功能:
<input v-on:keyup="doStuff">
methods: { doStuff: _.debounce(function () { // ... }, 500) }
這種寫法的更多優(yōu)點詳見:v-model
示例。
替換 limitBy
過濾器
不再這樣寫:
<p v-for="item in items | limitBy 10">{{ item }}</p>
在 computed 屬性中使用 js 內置方法:.slice
method:
<p v-for="item in filteredItems">{{ item }}</p>
computed: { filteredItems: function () { return this.items.slice(0, 10) } }
替換 filterBy
過濾器
不再這樣寫:
<p v-for="user in users | filterBy searchQuery in 'name'">{{ user.name }}</p>
在 computed 屬性中使用 js 內置方法 .filter
method:
<p v-for="user in filteredUsers">{{ user.name }}</p>
computed: { filteredUsers: function () { var self = this return self.users.filter(function (user) { return user.name.indexOf(self.searchQuery) !== -1 }) } }
js 原生的 .filter
同樣能實現(xiàn)很多復雜的過濾器操作,因為可以在計算 computed 屬性中使用所有 js 方法。比如,想要通過匹配用戶名字和電子郵箱地址 (不區(qū)分大小寫) 找到用戶:
var self = this self.users.filter(function (user) { var searchRegex = new RegExp(self.searchQuery, 'i') return user.isActive && ( searchRegex.test(user.name) || searchRegex.test(user.email) ) })
替換 orderBy
過濾器
不這樣寫:
<p v-for="user in users | orderBy 'name'">{{ user.name }}</p>
而是在 computed 屬性中使用 lodash’s orderBy
(或者可能是 sortBy
):
<p v-for="user in orderedUsers">{{ user.name }}</p>
computed: { orderedUsers: function () { return _.orderBy(this.users, 'name') } }
甚至可以字段排序:
_.orderBy(this.users, ['name', 'last_login'], ['asc', 'desc'])
升級方式
運行遷移工具找到指令中使用的過濾器。如果有些沒找到,看看控制臺錯誤信息。
過濾器參數(shù)符號 變更
現(xiàn)在過濾器參數(shù)形式可以更好地與 js 函數(shù)調用方式一致,因此不用再用空格分隔參數(shù):
<p>{{ date | formatDate 'YY-MM-DD' timeZone }}</p>
現(xiàn)在用圓括號括起來并用逗號分隔:
<p>{{ date | formatDate('YY-MM-DD', timeZone) }}</p>
升級方式
運行遷移工具找到老式的調用符號,如果有遺漏,請看控制臺錯誤信息。
內置文本過濾器 移除
盡管插入文本內部的過濾器依然有效,但是所有內置過濾器已經(jīng)移除了。取代的是,推薦在每個區(qū)域使用更專業(yè)的庫來解決。(比如用 date-fns
來格式化日期,用 accounting
來格式化貨幣)。
對于每個內置過濾器,我們大概總結了下該怎么替換。代碼示例可能寫在自定義 helper 函數(shù),方法或計算屬性中。
替換 json
過濾器
不用一個個改,因為 Vue 已經(jīng)幫你自動格式化好了,無論是字符串,數(shù)字還是數(shù)組,對象。如果想用 js 的 JSON.stringify
功能去實現(xiàn),你也可以把它寫在方法或者計算屬性里面。
替換 capitalize
過濾器
text[0].toUpperCase() + text.slice(1)
替換 uppercase
過濾器
text.toUpperCase()
替換 lowercase
過濾器
text.toLowerCase()
替換 pluralize
過濾器
NPM 上的 pluralize 庫可以很好的實現(xiàn)這個功能。如果僅僅想將特定的詞格式化成復數(shù)形式或者想給特定的值 (‘0’) 指定特定的輸出,也可以很容易地自定義復數(shù)格式化過濾器:
function pluralizeKnife (count) { if (count === 0) { return 'no knives' } else if (count === 1) { return '1 knife' } else { return count + 'knives' } }
Replacing the currency
Filter
對于簡單的問題,可以這樣做:
'$' + price.toFixed(2)
大多數(shù)情況下,仍然會有奇怪的現(xiàn)象 (比如 0.035.toFixed(2)
向上取舍得到 0.04
,但是 0.045
向下取舍卻也得到 0.04
)。解決這些問題可以使用 accounting
庫來實現(xiàn)更多可靠的貨幣格式化。
升級方式
運行遷移工具找到舍棄的過濾器。如果有些遺漏,請參考控制臺錯誤信息。
雙向過濾器 替換
有些用戶已經(jīng)樂于通過 v-model
使用雙向過濾器,以很少的代碼創(chuàng)建有趣的輸入。盡管表面上很簡單,雙向過濾器也會暗藏一些巨大的復雜性——甚至促使狀態(tài)更新變得遲鈍影響用戶體驗。推薦用包裹一個輸入的組件取而代之,這樣以更顯性且功能更豐富的方式創(chuàng)建自定義的輸入。
我們現(xiàn)在做一次雙向匯率過濾器的遷移作為示范:
它基本工作良好,但是拖延的狀態(tài)更新會導致奇怪的行為。比如,點擊 Result
標簽,試著在其中一個輸入框中輸入 9.999
。當輸入框失去焦點的時候,其值將會更新到 $10.00
。然而當我們從整個計算器的角度看時,你會發(fā)現(xiàn)存儲的數(shù)據(jù)是 9.999
。用戶看到的已經(jīng)不是真實的同步了!
為了過渡到一個更加健壯的 Vue 2.0 的方案,讓我們首先在一個新的 <currency-input>
組件中包裹這個過濾器:
它允許我們添加獨立過濾器無法封裝的行為,比如選擇輸入框聚焦的內容。下一步我們從過濾器中提取業(yè)務邏輯。接下來是我們把所有的東西放到一個外部的 currencyValidator
對象中:
這會更加模塊化,不只是更容易的遷移到 Vue 2,同時也允許匯率間隙和格式化:
從你的 Vue 代碼中獨立出來進行單元測試
在你的應用程序的別的部分中使用,比如驗證驗證一個 API 端的負荷
把這個驗證器提取出來之后,我們也可以更舒適的把它構建到更健壯的解決方案中。那些古怪的狀態(tài)也消除了,用戶不再可能會輸入錯誤,就像瀏覽器原生的數(shù)字輸入框一樣。
然而在 Vue 1.0 的過濾器中,我們仍然是受限的,所以還是完全升級到 Vue 2.0 吧:
你可能注意到了:
我們的輸入框的各方面都更顯性,使用生命周期鉤子和 DOM 事件以替代雙向過濾器的隱藏行為。
我們現(xiàn)在可以在自定義輸入框中直接使用
v-model
,其不只是固定配合正常的輸入框來使用,這也意味著我們的組件是對 Vuex 友好的。因為我們已經(jīng)不再要求過濾器選項必須要有一個返回值,所以實際上我們的匯率工作可以異步完成。這意味著如果我們有很多應用需要和匯率打交道,我們可以輕松的提煉這個邏輯并成為一個共享的微服務。
升級方式
運行遷移工具找到在例如 v-model
的指令中使用過濾器的例子。如果你錯過了,則應該會收到命令行報錯。
插槽
重名的插槽 移除
同一模板中的重名 <slot>
已經(jīng)棄用。當一個插槽已經(jīng)被渲染過了,那么就不能在同一模板其它地方被再次渲染了。如果要在不同位置渲染同一內容,可以用 prop 來傳遞。
升級方式
更新后運行測試,查看控制臺警告信息 關于重名 slots 的提示 v-model
。
slot
樣式參數(shù) 移除
通過具名 <slot>
插入的片段不再保持 slot
的參數(shù)。請用一個包裹元素來控制樣式?;蛘哂酶呒壏椒ǎ和ㄟ^編程方式修改內容 :render functions。
升級方式
運行遷移工具找到選擇 slots 標簽 CSS 選擇器 (例如:[slot="my-slot-name"]
)。
特殊屬性
keep-alive
屬性 替換
keep-alive
不再是一個特殊屬性而是一個包裹組件,類似于 <transition>
比如:
<keep-alive> <component v-bind:is="view"></component> </keep-alive>
這樣可以在含多種狀態(tài)子組件中使用 <keep-alive>
:
<keep-alive> <todo-list v-if="todos.length > 0"></todo-list> <no-todos-gif v-else></no-todos-gif> </keep-alive>
當
<keep-alive>
含有不同子組件時,應該分別影響到每一個子組件。不僅是第一個而是所有的子組件都將被忽略。
和 <transition>
一起使用時,確保把內容包裹在內:
<transition> <keep-alive> <component v-bind:is="view"></component> </keep-alive> </transition>
升級方式
運行遷移工具找到keep-alive
屬性。
計算插值
屬性內部的計算插值 移除
屬性內部的計算插值已經(jīng)不能再使用了:
<button class="btn btn-{{ size }}"></button>
應該寫成行內表達式:
<button v-bind:class="'btn btn-' + size"></button>
或者計算屬性:
<button v-bind:class="buttonClasses"></button>
computed: { buttonClasses: function () { return 'btn btn-' + size } }
升級方式
運行遷移工具找到屬性內部的計算插值
HTML 計算插值 移除
HTML 的計算插值 ({{{ foo }}}
) 已經(jīng)移除,取代的是 v-html
指令。
升級方式
運行遷移工具找到 HTML 計算插值。
單次綁定替換
單次綁定 ({{* foo }}
) 已經(jīng)被新的 v-once
directive 取代。
升級方式
運行遷移工具找到單次綁定使用位置。
響應
vm.$watch
changed
通過 vm.$watch
創(chuàng)建的觀察器現(xiàn)在將在組件渲染時被激活。這樣可以讓你在組件渲染前更新狀態(tài),不用做不必要的更新。比如可以通過觀察組件的 prop 變化來更新組件本身的值。
如果以前通過 vm.$watch
在組件更新后與 DOM 交互,現(xiàn)在就可以通過updated
生命周期鉤子來做這些。
升級方式
運行測試,如果有依賴于老方法的觀察器將彈出 failed tests。
vm.$set
變更
vm.$set
只是 Vue.set
的別名。
升級方式
運行遷移工具找到過時的用法
vm.$delete
變更
vm.$delete
現(xiàn)在只是:Vue.delete
別名。
升級方式
運行遷移工具找到過時的用法
Array.prototype.$set 棄用
用 Vue.set
替代
升級方式
運行遷移工具找到數(shù)組上的.$set
。如有遺漏請參考控制臺錯誤信息。
Array.prototype.$remove
移除
用 Array.prototype.splice
替代,例如:
methods: { removeTodo: function (todo) { var index = this.todos.indexOf(todo) this.todos.splice(index, 1) } }
或者更好的方法,直接給除去的方法一個 index 參數(shù):
methods: { removeTodo: function (index) { this.todos.splice(index, 1) } }
升級方式
運行遷移工具找到數(shù)組上的.$remove
。如有遺漏請參考控制臺錯誤信息。
Vue 實例上的Vue.set
和 Vue.delete
移除
Vue.set
和 Vue.delete
在實例上將不再起作用?,F(xiàn)在都強制在實例的 data 選項中聲明所有頂級響應值。如果刪除實例屬性或實例$data
上的某個值,直接將它設置為 null 即可。
升級方式
運行遷移工具找到實例中的 Vue.set
或 Vue.delete
。如有遺漏請參考控制臺錯誤信息。
替換 vm.$data
移除
現(xiàn)在禁止替換實例的 $data。這樣防止了響應系統(tǒng)的一些極端情況并且讓組件狀態(tài)更加可控可預測 (特別是對于存在類型檢查的系統(tǒng))。
升級方式
運行遷移工具找到覆蓋 vm.$data
的位置。如有遺漏請參考 控制臺警告信息。
vm.$get
移除
可以直接取回響應數(shù)據(jù)。
升級方式
運行遷移工具找到 vm.$get
的位置。如有遺漏請參考 控制臺錯誤信息。
圍繞 DOM 的實例方法
vm.$appendTo
移除
使用 DOM 原生方法:
myElement.appendChild(vm.$el)
升級方式
運行遷移工具找到 vm.$appendTo
的位置。如果有遺漏可以參考 控制臺錯誤信息。
vm.$before
移除
使用 DOM 原生方法:
myElement.parentNode.insertBefore(vm.$el, myElement)
升級方式
運行遷移工具找到 vm.$before
。如有遺漏,請參考 控制臺錯誤信息。
vm.$after
移除
使用 DOM 原生方法:
myElement.parentNode.insertBefore(vm.$el, myElement.nextSibling)
如果 myElement 是最后一個節(jié)點也可以這樣寫:
myElement.parentNode.appendChild(vm.$el)
升級方式
運行遷移工具找到 vm.$after
的位置。如有遺漏,請參考 控制臺錯誤信息。
vm.$remove
移除
使用 DOM 原生方法:
vm.$el.remove()
升級方式
運行遷移工具找到vm.$remove
。如有遺漏,請參考 控制臺錯誤信息。
底層實例方法
vm.$eval
移除
盡量不要使用,如果必須使用該功能并且不肯定如何使用請參考 the forum。
升級方式
運行遷移工具找到使用 vm.$eval
的位置。如有遺漏請參考 控制臺錯誤信息。
vm.$interpolate
移除
盡量不要使用,如果必須使用該功能并且不肯定如何使用請參考 the forum。
升級方式
運行遷移工具找到vm.$interpolate
。如有遺漏請參考 控制臺錯誤信息。
vm.$log
移除
請使用 Vue Devtools 感受最佳 debug 體驗。
升級方式
運行遷移工具找到 vm.$log
。如有遺漏請參考控制臺錯誤信息。
實例 DOM 選項
replace: false
移除
現(xiàn)在組件總是會替換掉他們被綁定的元素。為了模仿replace: false
的行為,可以用一個和將要替換元素類似的元素將根組件包裹起來:
new Vue({ el: '#app', template: '<div id="app"> ... </div>' })
或者使用渲染函數(shù):
new Vue({ el: '#app', render: function (h) { h('div', { attrs: { id: 'app', } }, /* ... */) } })
升級方式
運行遷移工具找到 replace: false
使用的位置。
全局配置
Vue.config.debug
移除
不再需要,因為警告信息將默認在堆棧信息里輸出。
升級方式
運行遷移工具找到包含Vue.config.debug
的地方。
Vue.config.async
移除
異步操作現(xiàn)在需要渲染性能的支持。
升級方式
運行遷移工具找到使用 Vue.config.async
的實例。
Vue.config.delimiters
替換
以模板選項的方式使用。這樣可以在使用自定義分隔符時避免影響第三方模板。
升級方式
運行遷移工具找到使用 Vue.config.delimiters
的實例。
Vue.config.unsafeDelimiters
移除
HTML 插值替換為 v-html
。
升級方式
運行遷移工具來找到 Vue.config.unsafeDelimiters
。然后 helper 工具也會找到 HTML 插入的實例,可以用`v-html`來替換。
全局 API
帶 el
的 Vue.extend
移除
el 選項不再在 Vue.extend
中使用。僅在實例創(chuàng)建參數(shù)中可用。
升級方式
更新后運行測試在控制臺警告信息中找到關于帶有Vue.extend
的el
。
Vue.elementDirective
移除
用組件來替代
升級方式
運行遷移工具找到包含Vue.elementDirective
的實例。
Vue.partial
移除
Partials 已被移除,取而代之的是更明確的組件之間的數(shù)據(jù)流–props。除非你正在使用一個部分性能關鍵型區(qū)域,否則建議只使用一個 normal component 來代替。如果你是動態(tài)綁定部分的 name
,您可以使用 dynamic component。
如果你碰巧在你的應用程序的性能關鍵部分使用 partials,那么你應該升級到函數(shù)式組件。它們必須在純 JS / JSX 文件中 (而不是在 .vue
文件中),并且是無狀態(tài)的和無實例的,就像 partials。這使得渲染極快。
函數(shù)式組件相對于 partials 一個好處是它們可以更具動態(tài)性,因為它們允許您訪問 JavaScript 的全部功能。然而,這是有成本的。如果你從來沒有使用過渲染式的組件框架,你可能需要花費更長的時間來學習它們。
升級方式
運行遷移工具找到包含 Vue.partial
的實例