Vue 的下一代版本(3.0)終于在9.18日發(fā)布正式版了,代號(hào)居然叫“One Piece”,不知海賊王粉們會(huì)作何感想... 不過終極秘寶這個(gè)定位,倒是很符合大家對(duì)這個(gè)版本的期待。去年開始,3.0版本的各種消息就一直源源不斷,我只是粗略的了解了一下,只知道這個(gè)版本在性能和架構(gòu)上都會(huì)有革命性的升級(jí),因?yàn)樵缙诘陌姹究隙o法直接應(yīng)用到項(xiàng)目上,各種API和實(shí)現(xiàn)細(xì)節(jié)也會(huì)不斷變化,我也就沒有深入去了解版本升級(jí)變化的各種細(xì)節(jié)。但現(xiàn)在正式版已經(jīng)發(fā)布了,核心生態(tài)圈的框架適配工作(vue-router 4.0,vuex4.0,Ant Design Vue 2.0等)也接近完成,現(xiàn)在是時(shí)候可以評(píng)估一下將3.0版本引入到實(shí)際業(yè)務(wù)開發(fā)的可行性了。
響應(yīng)式機(jī)制的革新
3.0版本最重大的變化將響應(yīng)式的實(shí)現(xiàn)機(jī)制從2.x的Object.defineProperty方式更改為使用ES2015的Proxy機(jī)制,這樣不但能夠提升性能,而且原來無法自動(dòng)監(jiān)聽的對(duì)象屬性的增刪,數(shù)組元素和長(zhǎng)度的變化(2.x版本需要顯式調(diào)用Vue.$set方法),3.0版本可以直接自動(dòng)進(jìn)行監(jiān)聽和跟蹤了。但也不是完全沒有代價(jià),Proxy在IE系列瀏覽器上沒有被實(shí)現(xiàn),所以3.0版本目前還無法兼容IE11瀏覽器。但似乎可以通過引入Babel-polyfill在IE11上模擬Proxy實(shí)現(xiàn),這個(gè)還需要進(jìn)一步確認(rèn)。
Composition API
Vue 3.0現(xiàn)在擁有兩套相互獨(dú)立的組件構(gòu)建方式,一個(gè)還是原來基于配置式的Option Api,代碼的是通過配置項(xiàng)的類型來組織的,比如方法就放到methods下面,數(shù)據(jù)就放到data下面,向下面這樣:
export default {
data() {
return { count: 4 }
},
created() {
this.increment();
},
methods: {
increment() {
this.count++
console.log("current count:"+this.count);
}
}
}
這套配置規(guī)則和2.x版本基本保持了一致,可以讓絕大部分老用戶無感的直接過渡到3.0版本。同時(shí),為了實(shí)現(xiàn)對(duì)TypeScript更好的結(jié)合和支持(3.0的版本本身就是使用TypeScript開發(fā)的),并且強(qiáng)化組件中業(yè)務(wù)邏輯的可復(fù)用性,3.0版本還提供了一套基于類和方法的全新的Composition API,可以更加靈活的構(gòu)建所需要的組件。比如把上面的例子改成Composition API的寫法:
import { ref , onMounted } from 'vue'
export default {
setup(props) {
const counter = ref(0) //初始化一個(gè)響應(yīng)式的數(shù)字
const increment = () => {
counter.value ++
console.log("current count:"+counter.value);
}
onMounted(increment) //這是一個(gè)生命周期方法
return {
count:counter.value,
increment
} // 這里返回的東西在整個(gè)組件中都可以通過this指針進(jìn)行訪問
}
// 組件的其它部分
}
其中setup是Composition API的入口函數(shù),會(huì)在整個(gè)組件創(chuàng)建之前被執(zhí)行??梢钥闯?,使用Composition API我們可以完全基于編碼的方式構(gòu)建整個(gè)組件,并設(shè)置組件的各種特性,這樣非常直觀,也能很方便利用TypeScript強(qiáng)類型的各種好處,不像2.x版本使用TypeScript時(shí)強(qiáng)行利用注解來轉(zhuǎn)換這么別扭。Option API中可以設(shè)置的配置項(xiàng),在Composition API都能找到對(duì)應(yīng)的東西,比如watch,computed,還有各種生命周期方法。不過都需要顯式的import才可以使用。有幾個(gè)函數(shù)需要重點(diǎn)關(guān)注一下:
- reactive:作用于一個(gè)對(duì)象,返回這個(gè)對(duì)象的一個(gè)響應(yīng)式副本。以前只有聲明在組件data配置下的屬性才具備響應(yīng)式特征,但通過這個(gè)新的函數(shù)我們可以給任意的數(shù)據(jù)增添響應(yīng)式的特性,而且這個(gè)特性不會(huì)因?yàn)閰?shù)傳遞而消失。響應(yīng)式轉(zhuǎn)換是深度嵌套的,這個(gè)對(duì)象的任意嵌套屬性也會(huì)被轉(zhuǎn)換。用法如下:
const obj = reactive({ count: 0 })
obj.count ++
- ref:這個(gè)函數(shù)上面的例子也出現(xiàn)過,作用和reactive類似,也是為數(shù)據(jù)增加響應(yīng)式特性,我的理解它更像一個(gè)包裝函數(shù),主要用于對(duì)基礎(chǔ)數(shù)據(jù)類型(字符串,數(shù)值,布爾等等)進(jìn)行封裝(reactive函數(shù)無法作用于基礎(chǔ)類型數(shù)據(jù)),返回一個(gè)引用對(duì)象,引用對(duì)象只有一個(gè)屬性value,指向內(nèi)部所包裝的數(shù)據(jù)。如果封裝的類是一個(gè)對(duì)象,則會(huì)直接使用上面的reactive函數(shù)進(jìn)行嵌套轉(zhuǎn)換。如果直接在template中使用ref的話,會(huì)自動(dòng)進(jìn)行拆箱,無需再調(diào)用value屬性。用法如下:
const count = ref(0)
count.value++
- readonly:可以作用于響應(yīng)式對(duì)象或普通對(duì)象,返回一個(gè)該對(duì)象的一個(gè)自讀的代理對(duì)象。如果修改對(duì)象屬性會(huì)失敗并引發(fā)警告。
TypeScript支持:
JavaScript本身是沒有編譯期檢查的,開發(fā)中小型應(yīng)用還覺得沒什么問題,但是隨著項(xiàng)目規(guī)模的擴(kuò)大,特別是后面需要重構(gòu)代碼的時(shí)候,修改對(duì)象的屬性或者類型就需要非常小心了,稍不留意漏改了引用的地方就會(huì)引發(fā)運(yùn)行錯(cuò)誤。這個(gè)讓我這種同時(shí)也使用Java這類強(qiáng)類型語言的人感覺非常無奈。而TypeScript主要就是解決這個(gè)問題的,TypeScript為JavaScript引入了靜態(tài)類型系統(tǒng),同時(shí)保留了語法上的靈活性,意味著可以在編譯期提前發(fā)現(xiàn)更多潛在的錯(cuò)誤,有利于開發(fā)規(guī)模更大的前端應(yīng)用程序。
Vue 3.0版本本身就是使用TypeScript全新開發(fā)的,意味著對(duì)TypeScript的內(nèi)置支持,不需要再像2.x版本那樣需要引入第三方庫才能勉強(qiáng)使用TypeScript的特性了。詳細(xì)的變化可以參考 TypeScript Support | Vue.js