今天看了vue2升遷vue3相關知識,這里列舉一部分比較常用的不同之處
v-for數組中的ref屬性的使用(這個屬性是非兼容的)
- vue2: 使用this.$refs[屬性名]的方式獲取到一個元素數組
<div v-for="(item,index) in list" ref="setItemRef" :key="index">
{{item.name}}
</div>
<button @click="getRef">獲取ref</button>
export default {
data() {
return {
list: [
{ name: '小錢1'},
{ name: '小花'}
]
};
},
methods: {
getRef() {
console.log(this.$refs.setItemRef) // (2) [div, div]
}
}
}
- vue3:
不再通過this.$refs方式獲取,而是通過一個同名函數去獲取對應元素,這個函數,你只需要定義,vue3會自調用它,不需要手動調用。
此外,可以使用一個數組對象來保存獲取到的元素集合,它返回是一個類數組的Proxy對象,這樣還可以起到防止用戶直接篡改數組來改變元素
<div v-for="(item,index) in list" ref="setItemRef" :key="index">
{{item.name}}
</div>
<button @click="getRef">獲取ref</button>
export default {
data() {
return {
itemRefs: []
}
},
methods: {
setItemRef(el) {
this.itemRefs.push(el)
},
getRef() {
console.log(this.itemRefs) // 類數組的Proxy對象,[div, div], itemRefs可以定義為數組,也可以定義為對象
}
}
}
$children
vue2中可以通過this.$children獲取當前組件的所有子組件對象
vue3中已刪除此API,可以使用this.$ref[子組件的ref名稱]來替代獲取
插槽的改變
vue2.5以前,插槽的使用方式是:
<!-- slot-comp -->
<template>
<div>
<slot name="hasData" :data="data" age="18"></slot>
</div>
</template>
<!-- parent -->
<slot-comp>
<!-- 傳統寫法:帶數據的插槽, slotData是所有寫在slot插槽上的屬性集合 -->
<template slot="hasData" slot-scope="slotData">
<!-- { "data": [ 1, 2, 3 ], "age": "18" } -->
{{slotData}}
</template>
</slot-comp>
vue2.6時,已改為v-slot的方式,文檔中雖然說廢除之前的傳統寫法,但在實際中,還是向下兼容的,所以在vue2中使用哪種方式目前都是可以的
<!-- slot-comp -->
<template>
<div>
<!-- 帶數據的插槽:作用域插槽 -->
<slot name="hasData" :data="data" age="18"></slot>
</div>
</template>
<!-- parent -->
<slot-comp>
<!-- 縮寫寫法: <template #:hasData="data"> -->
<template v-slot:hasData="data">
<!-- { "data": [ 1, 2, 3 ], "age": "18" } -->
{{data}}
</template>
</slot-comp>
在vue3時,不再向下兼容,只支持v-slot的寫法(也可以縮寫為#):
在element-ui中就使用的是vue2.5以前的傳統插槽方式;
element-plus就改為了vue3支持的#(v-slot)寫法,所以說element-ui不支持vue3也有這個原因
響應式
- vue2的響應式是使用defineProperty來對數據劫持的,它有大的局限性:
- 需要遍歷data中的對象,來綁定劫持數據,如果對象嵌套對象,那么需要遞歸遍歷調用defineProperty來實現響應式,當對象嵌套很深時,對性能消耗會很大
- 不支持數組中對象的響應式,包括現在還有這個bug,通過數組下標改變一下對象,是無法做到響應式的;尤大大自己也回復說,是因為性能問題,所以才沒實現,這還是跟第1個遞歸遍歷有關,當嵌套過多,性能會比較差
export default {
data() {
return {
list: [
{ name: '小錢1'},
{ name: '小花'}
]
};
},
methods: {
change() {
this.list[0] = { name: '小飛' } // 在頁面中是不響應的
}
}
}
- 不支持對象的增加或刪除響應式
- vue3使用Proxy,它自然地監聽對象下的所有屬性,解決了vue2響應式的問題,因為不需要遞歸去遍歷,所以它本身的性能就很好
composition API
- vue2支持的是options API:
當我們要修改一個變量時,它如果涉及到很多地方,比如data中定義,在某個methods中修改,然后可能watch時也會修改,業務代碼是離散的;
當文件很大時,每次修改相關業務,我們都要滑動鼠標去查找對應的好些地方才能修改完,一個是麻煩,二個是很容易漏改某處,開發體驗不是很好。
- vue3支持composition API,它將業務有聯系的代碼統一放到setup函數中,當修改時,我們可以集中修改這塊業務代碼
- 開發體驗好,修改起來集中且容易查找
- 因為業務代碼集中,更靈活的邏輯組織,方便拆分和抽象組件,更利于組件復用
- 沒有this,再也不用糾結this上到底有什么
- 更友好的tree-shaking支持
- 更大的代碼壓縮空間
- 更好的類型推導能力(typescript),因為setup本質是一個函數,它的輸入和輸出是固定的,所以能更好推導類型
composition API語法
compostion API都是寫在一個setup的方法中:
- 一般使用ref來定義基礎類型數據
- 使用reactive來定義數組或對象
- 跟上面變量相關的方法也都定義在setup方法中,定義寫法和普通的方法一樣
- 無論定義的是什么,都要return出去才生效
- setup的生命周期:
- setup是在beforeCreate生命周期前執行:setup -> beforeCreate -> created
- setup中也有自己的生命周期函數,即vue的生命周期(除了beforeCreate和created兩個)前加'on',就是它的生命周期倒數,比如onMounted,但是所有生命周期都必須寫在return前面
- 要使用的生命周期必須從vue導入(PS:之前的ref、reactive定義變量的方法也要導入)
composition API的實現:
// 導入ref, reactive, onMounted
import { reactive, computed, onMounted } from 'vue'
export default {
setup() {
console.log('setup')
// 基礎類型的定義
const x = Ref(x)
// 數組或對象定義
const obj = reactive({
name: 'xx',
list: ['xxx']
})
function changeX() {
x.value = 22
obj.name = 'xxx'
}
// setup中的生命周期
onMounted() {
obj.name = 'xx2'
}
// 無論是什么,都必須return出去才生效
return {
x,
obj,
changeX
}
},
beforeCreate() {
console.log('beforeCreate')
},
created() {
console.log('created')
}
}
項目升級評估(是否要從vue2升級到vue3):
項目量級及業務需求
如果項目非常大(比如沉淀好幾年的老項目,基數非常大),且業務非常復雜(需求不熟悉的話根本理不清,改一處n個bug那種),建議不要升!
業務對技術升級是不是有要求,有要求才升級,不要因為想使用新技術而升級,要從業務角度出發團隊能力
如果團隊能力水平參差不齊的話,有的人對vue3很了解,有的人壓根不會,那很有可能因為團隊能力不齊導致升級失敗不兼容代碼評估
一定一定要參考官網升遷文檔:https://vue3js.cn/docs/zh/guide/migration/functional-components.html#_2-x-%E8%AF%AD%E6%B3%95
明確升遷的變動范圍和成本第3方擴展插件評估
評估下原項目使用的插件,在vue3中是否已經有了對應的升遷擴展,目前vuex,vue-router,element-plus都支持vue3的版本,但還要考慮項目中其它插件綜合成本評估
從人力、時間、花費等方面去綜合考慮
詳細的還是推薦大家仔細閱讀下官網:
https://v3.vuejs.org/guide/introduction.html#conditionals-and-loops
https://vue3js.cn/docs/zh/guide/migration/functional-components.html#_2-x-%E8%AF%AD%E6%B3%95