距離Vue 3.0正式發佈已經過去一段時間了,2月7日Vue團隊正式宣佈Vue 3正式成為新的預設版本。最近接觸的新項目也使用Vue 3.0來開發,因此有必要對它進行一波總結和學習。 ...
1 前言
距離Vue 3.0正式發佈已經過去一段時間了,2月7日Vue團隊正式宣佈Vue 3正式成為新的預設版本。最近接觸的新項目也使用Vue 3.0來開發,因此有必要對它進行一波總結和學習。
2 簡介
在最開始的時候,Vue僅僅是一個運行時庫。但經過多年的發展,它已經逐漸變成了一臺包含許多子項目的框架。Vue的核心庫只關註圖層,不僅易於上手,還便於與第三方庫或既有項目整合。那麼Vue 3.0帶來了哪些新的表現呢?
- 重寫了虛擬Dom
- 編譯模板的優化
- 更高效的組件初始化
- SSR速度提高了2~3倍
- 更新性能提高了1.3~2倍
- 看起來Vue 3相比於2性能上有了很大的提升,作為終端用戶的我們,還是來看看代碼是如何實現的吧。
3 新的特性
3.1 組合式API
Vue 2中採用的是Options API(選項式API),即在data、methods、computed、watch中分別寫入代碼,如果我們需要增加一個邏輯,就需要在這些選項中反覆橫跳,導致組件難以理解和閱讀。Vue 3新增了setup選項,它是組合式API的入口。它將同一個邏輯關註點相關代碼收集在一起,這樣我們需要維護一個功能點的時候,就不需要去關心其他的邏輯。
舉個例子
<template>
<div>{{number}}</div>
<button @click="add">Add</button>
</template>
<script>
import { ref } from 'vue'
export default {
setup () {
const number = ref(0) //ref()函數使變數變為響應式
const add = () => {
number.value++ //使用ref創建的響應式變數需要加.value
}
return { //返回的變數和方法可以在模板中直接使用
number,
add
}
}
}
</script>
這看起來不就是把data、methods中的內容都放到setup里了嗎,也沒多大區別啊?其實,我們還可以把setup裡面的內容分割成一個個獨立的函數,每個函數負責獨立的功能。這樣,我們就可以在不同組件中進行復用,簡潔代碼,這才是組合式API的強大之處。
3.2 響應式API
3.2.1 ref
在上面的代碼中我們使用了ref創建了響應式對象,它接受js基本類型或引用類型作為參數,返回的就是一個只包含名為value參數的RefImp對象。在setup函數中如果我們要使用該響應式對象,就需要加上.value。但是在模板中被渲染時,自動展開內部的值,因此不需要在模板中追加.value。
ref常用於基礎類型,如果ref傳入對象,其內部會轉換為reactive進行處理。
import { ref } from "vue";
const str = ref("");
const male = ref(true);
str.value = "new val";
console.log(str.value); //new val
male.value = false;
console.log(male.value) //fals
3.2.2 reactive
reactive函數只接收object和array等複雜數據類型,它會返回一個proxy對象。reactive可以深層次遞歸,也就是如果發現展開的屬性值是引用類型的而且被引用,還會用reactive遞歸處理。而且屬性是可以被修改的。 proxy是es6中用於創建一個對象的代理函數,可以實現對目標對象的增刪改查等基本操作的攔截和自定義。
const p=new Proxy(target,handler) //target是proxy包裝的目標對象,handler是一個以函數作為屬性的對象
簡單模擬實現reactive實現響應式:
const obj={a:1,b:2}
const p=new Proxy(obj,{
get(target,key){
console.log(`p的${key}屬性被訪問了!`)
return Reflect.get(target,key)
},
set(target,key,value){
console.log(`p的${key}屬性被修改了!`)
return Reflect.set(target,key,value)
},
deleteProperty(target,key){
console.log(`p的${key}屬性被刪除了!`)
return Reflect.deleteProperty(target,key)
}
})
3.2.3 toRefs
通過上面的介紹我們已經知道了ref通常用來創建基礎類型數據的雙向綁定,reactive通常用來創建引用數據類型的雙向綁定。除此之外,ref也可以創建複雜類型的雙向綁定,而reactive不能代理基礎類型。我們來看一個例子:
<template>
<div>{{user.name}}</div>
<div>{{user.age}}</div>
<div>{{user.sex}}</div>
<button @click="changeInfo">更改個人信息</button>
</template>
<script>
import { ref } from 'vue'
export default {
setup () {
const user = ref({name:'張三',age:'18',sex:'男'})
const changeInfo = () => {
user.name.value='李四'
user.age=20
user.sex='女'
}
return {
user
}
}
}
</script>
上面的代碼中我們綁定到頁面使用的是user.name,user.age,這樣寫感覺很繁瑣,那能通過解構解構user然後在模板中直接使用嗎?答案是不能的,這樣做會使user丟失掉響應式。但是通過使用toRefs,就可以直接使用解構後的數據了。 toRefs 用於將一個 reactive 對象轉化為屬性全部為 ref 對象的普通對象。具體使用方式如下:
<template>
<div>{{name}}</div>
<div>{{age}}</div>
<div>{{sex}}</div>
<button @click="changeInfo">更改個人信息</button>
</template>
<script>
import { ref } from 'vue'
export default {
setup () {
const user = ref({name:'張三',age:'18',sex:'男'})
const changeInfo = () => {
user.name.value='李四'
user.age=20
user.sex='女'
}
return {
...toRefs(user) //使用toRefs
}
}
}
3.3 響應式偵聽
watch 函數用來偵聽特定的數據源,併在回調函數中執行副作用。預設情況是惰性的,也就是說僅在偵聽的源數據變更時才執行回調。
watch(source,callback,[options])
- source:可以支持 string,Object,Function,Array; 用於指定要偵聽的響應式變數
- callback:執行的回調函數
- options:可選項,支持 deep、immediate 和 flush
監聽單個數據源的用法:
import { reactive, ref, watch } from "vue";
const state = reactive({
number:0,
id:'01'
});
//偵聽reative對象
watch(
() => state.number,
(newvalue, oldvalue) => {
console.log(newvalue, oldvalue); //1 0
}
);
state.number++;
const count = ref(0);
//偵聽ref對象
watch(count, (count, prevCount) => {
console.log(count, prevCount, "watch"); //2 0
});
count.value = 2
監聽多個數據源的用法:
import { reactive, ref, watch } from "vue";
const state = reactive({
number:0,
id:'01'
});
const count = ref(0);
watch([count,()=>{state.number}],([curcount,precount],[curnumber,prenumber])=>{
console.log(curcount,precount) //2 0
console.log(curnumber,prenumber) //1 0
})
state.number++
count.value=2
對於多層嵌套的引用對象,可以使用{deep:true}開啟深度監聽。否則僅能監聽到外層數據變化。前面提到,預設清空下watch的回調函數是惰性的,只有當監聽數據變化時才會執行。當配置{immediate: true}時,可以立即執行回調函數。
3.4 生命周期
在Vue2中有8個生命周期函數:
- beforeCreate
- created
- beforeMount
- mounted
- beforeUpdate
- updated
- beforeDestroy
- destroyed
在vue3中,新增了一個setup生命周期函數,setup執行的時機是在beforeCreate生命函數之前執行,因此在這個函數中是不能通過this來獲取實例的;同時為了命名的統一,將beforeDestroy改名為beforeUnmount,destroyed改名為unmounted,因此vue3有以下生命周期函數:
- beforeCreate -> 不需要
- created -> 不需要
- beforeMount -> onBeforeMount
- mounted -> onMounted
- beforeUpdate -> onBeforeUpdate
- updated -> onUpdated
- beforeUnmount -> onBeforeUnmount
- unmounted -> onUnmounted
- errorCaptured -> onErrorCaptured
- renderTracked -> onRenderTracked
- renderTriggered -> onRenderTriggered
4 總結
通過對以上知識的總結對Vue 3有了進一步的認識,基本能夠滿足項目開發。更多的改動大家可以自行查閱官方文檔和閱讀源碼,相信Vue 3能給我們帶來更多新的體驗。
作者:京東物流 顏之婷
來源:京東雲開發者社區 自猿其說Tech