不是吧,兄弟,Vue3 都出來(lái)多久了,你還對(duì)這個(gè)感興趣,說(shuō)!是不是沒好好卷???
俺也一樣 ??,Vue3 出來(lái)之后只是簡(jiǎn)單了解了一下,然后還是轉(zhuǎn)頭一直在寫 Vue2。當(dāng)然,這也和大家搬磚??? 的處境有關(guān)。一般情況下,用 Vue2 起的項(xiàng)目沒有什么大的問(wèn)題,誰(shuí)又會(huì)耗費(fèi)經(jīng)歷去遷移呢?
不過(guò)自己在有機(jī)會(huì)單獨(dú)寫 H5 的時(shí)候,還是會(huì)有意識(shí)的去試試?Vue3 的。感覺 Vue2 如果掌握的不錯(cuò)的話,其實(shí)學(xué)習(xí) Vue3 也沒什么大的成本,但如果突然讓你總結(jié)一下 Vue2 和 Vue3 的區(qū)別,你能答上來(lái)多少呢?數(shù)據(jù)響應(yīng)式?生命周期?阿巴阿巴... ??
其實(shí)官方 Vue3 遷移指南?早就給出了詳細(xì)的說(shuō)明,這里對(duì)一些常用的做下些總結(jié),一起看看吧,Let's go!??
1. 語(yǔ)法上
1.1?指令模板相關(guān)
- 移除 v-on.native 修飾符
在 Vue 2 中,v-on.native 修飾符使得組件的事件偵聽器可以直接綁定到組件根元素上的原生事件。至于為什么要在 Vue3 中移除,網(wǎng)上有這樣的解釋:Vue2 這種方式并不符合組件的封裝和規(guī)范性,因?yàn)榻M件應(yīng)該將自己的行為和內(nèi)部實(shí)現(xiàn)細(xì)節(jié)封裝起來(lái),而不是直接依賴于父級(jí)組件的事件。
Vue 3 更加倡導(dǎo)組件的封裝性和獨(dú)立性,因此移除了v-on.native 修飾符,鼓勵(lì)使用更明確的方式進(jìn)行事件傳遞和處理。有道理 ??
- v-model 語(yǔ)法調(diào)整,v-model:title="title",代替了之前的 v-model 和 .sync
<!-- Vue2: -->
<ChildComponent v-model="pageTitle" />
<!-- 是以下的簡(jiǎn)寫: -->
<ChildComponent :value="pageTitle" @input="pageTitle = $event" />
<ChildComponent :title.sync="pageTitle" />
<!-- 是以下的簡(jiǎn)寫: -->
<ChildComponent :title="pageTitle" @update:title="pageTitle = $event" />
<!-- Vue3: -->
<ChildComponent v-model:title="pageTitle" />
<!-- 是以下的簡(jiǎn)寫: -->
<ChildComponent :title="pageTitle" @update:title="pageTitle = $event" />
1.2 組件相關(guān)
- 異步組件的調(diào)整,路由懶加載的組件需要用 defineAsyncComponent?關(guān)鍵字包裹 ??
- emit 選項(xiàng)可以定義組件可向父組件觸發(fā)的事件,同 props
// 數(shù)組語(yǔ)法
export default {
emits: ['check'],
created() {
this.$emit('check')
}
}
// 對(duì)象語(yǔ)法
export default {
emits: {
// 沒有驗(yàn)證函數(shù)
click: null,
// 具有驗(yàn)證函數(shù)
submit: (payload) => {
if (payload.email && payload.password) {
return true
} else {
console.warn(`Invalid submit event payload!`)
return false
}
}
}
}
1.3 渲染函數(shù)
- $listeners 合并至 $attrs
- $attrs 現(xiàn)在包含了所有傳遞給組件的 attribute,包括 class 和 style
1.4 移除的 API
- createApp() 代替 new Vue()
- ?從實(shí)例中完全移除了 $on、$off 和 $once 方法,通過(guò) new Vue() 方式實(shí)現(xiàn)的事件總線不再可用 ??。官方推薦用外部的、實(shí)現(xiàn)了事件觸發(fā)器接口的庫(kù),?如?mitt?或?tiny-emitter?
1.5 其他
- 根元素可以有不止一個(gè)標(biāo)簽了
- create 生命周期被 setup 代替,destroyed 被改名為 unmounted
- data 選項(xiàng)已標(biāo)準(zhǔn)化為只接受返回 object 的 function
- watch 可以偵聽數(shù)組時(shí)候,必須指定 deep 才能偵聽到數(shù)組元素的改變
- 新增了 <Teleport> 傳送門
- ref 支持函數(shù)了
2. 數(shù)據(jù)響應(yīng)式
2.1 Vue2 數(shù)據(jù)響應(yīng)式原理
老生常談的問(wèn)題,再贅述一遍 ??
Vue2 對(duì)數(shù)據(jù)的劫持是用的 Object.defineProperty,但這種方式其實(shí)是有缺點(diǎn)的 ??
- 對(duì)于未初始化但卻直接在 DOM?上引用的變量,并不能做到響應(yīng)式 ???補(bǔ)救:$set
- 對(duì)于數(shù)組類型的數(shù)據(jù),通過(guò)下標(biāo)改變的方式達(dá)不到響應(yīng)式 ???補(bǔ)救:使用改寫的數(shù)組 API
Object.defineProperty(obj, key, val) {
enumerable: true,
configurable: true,
get: function reactiveGetter() {
return val
},
set: function reactiveSetter(newVal) {
if(newVal === val) return
val = newVal
dep.notify() // 通知依賴該屬性的其他組件進(jìn)行更新
}
}
2.2?Vue3?數(shù)據(jù)響應(yīng)式原理
?Vue3 彌補(bǔ)了 Object.defineProperty 的兩個(gè)不足:
- Vue2 中動(dòng)態(tài)創(chuàng)建的 data 屬性需要通過(guò) Vue.$set 來(lái)賦,Proxy 則不需要
- 基于性能的考慮,Vue2 篡改了數(shù)組的 7 個(gè) API,Proxy 則不需要
defineProperty 需要提前遞歸遍歷 data 做到響應(yīng)式,而 Proxy可以在真正用到深層數(shù)據(jù)時(shí)候再做響應(yīng)式(惰性)????
funciton reactive(obj) {
return new Proxy(obj, {
get(target, key, receiver) {
const res = Reflect.get(target, key, receiver)
track(target, key) // 收集依賴
return isObject(res) ? reactive(res) : res
},
set(target, key, value, receiver) {
const oldValue = target[key]
const result = Reflect.set(target, key, value, receiver)
if(result && oldValue !== value) {
trigger(target, key) // 觸發(fā)更新
}
return result
}
})
}
3. Composition API
?Vue 官方:組合式 API 常見問(wèn)答:組合式 API (Composition API) 是一系列 API 的集合,使我們可以使用函數(shù)而不是聲明選項(xiàng)的方式書寫 Vue 組件。它是一個(gè)概括性的術(shù)語(yǔ),涵蓋了以下方面的 API:
在 Vue 3 中,組合式 API 基本上都會(huì)配合?<script setup>?語(yǔ)法在單文件組件中使用。下面是一個(gè)使用組合式 API 的組件示例:
<template>
<button @click="increment">點(diǎn)擊了:{{ count }} 次</button>
</template>
<script setup>
import { ref, onMounted } from 'vue'
// 響應(yīng)式狀態(tài)
const count = ref(0)
// 更改狀態(tài)、觸發(fā)更新的函數(shù)
function increment() {
count.value++
}
// 生命周期鉤子
onMounted(() => {
console.log(`計(jì)數(shù)器初始值為 ${count.value}。`)
})
</script>
為什么要用 Composition API?
Vue 官方:組合式 API 常見問(wèn)答?里也說(shuō)了為什么,比如更好的邏輯復(fù)用、類型推導(dǎo)、更靈活的代碼組織、更小的生產(chǎn)包體積。????
此外,我還了解大概是 2019 年?6月,尤雨溪發(fā)表了一篇 Composition API 的文章:「Vue Function-based API RFC」?,詳細(xì)闡述了為什么要出新的 API,其描述的設(shè)計(jì)思路大致總結(jié)如下:
-
響應(yīng)式 API:例如?
ref()
?和?reactive()
,使我們可以直接創(chuàng)建響應(yīng)式狀態(tài)、計(jì)算屬性和偵聽器。 -
生命周期鉤子??:例如?
onMounted()
?和?onUnmounted()
,使我們可以在組件各個(gè)生命周期階段添加邏輯。 -
依賴注入:例如?
provide()
?和?inject()
,使我們可以在使用響應(yīng)式 API 時(shí),利用 Vue 的依賴注入系統(tǒng)。 - Composition API 比 mixins、高階組件、Renderless Components 更好:
- 模版中的數(shù)據(jù)來(lái)源不清晰。舉例來(lái)說(shuō),當(dāng)一個(gè)組件中使用了多個(gè) mixin 的時(shí)候,光看模版會(huì)很難分清一個(gè)屬性到底是來(lái)自哪一個(gè) mixin。HOC 也有類似的問(wèn)題。
- 命名空間沖突。由不同開發(fā)者開發(fā)的 mixin 無(wú)法保證不會(huì)正好用到一樣的屬性或是方法名。HOC 在注入的 props 中也存在類似問(wèn)題。
- 性能。HOC 和 Renderless Components 都需要額外的組件實(shí)例嵌套來(lái)封裝邏輯,導(dǎo)致無(wú)謂的性能開銷。
- Composition API 更適合 TypeScript,Vue2 的裝飾器結(jié)合 TypeScript 非常難用。
ps:不知道大家有沒有關(guān)注過(guò) Vue3 的整個(gè)推出過(guò)程,我記得?Vue3 一開始公布的想法是推出一個(gè)基于 Class 的 API,忘記是在哪里偶然看到的了。那個(gè)時(shí)候 React 推出了 hooks 的概念,不知道是不是覺的 hooks 的概念更好,但是又不能直接叫 hooks API,所以就叫 Composition API。
此外,當(dāng)時(shí)還有一個(gè)潮流,大家好像都在從 JS 往 TS 上靠,Vue 應(yīng)該也想和 TypeScript 結(jié)合的更緊密,單 Vue2 裝飾器的寫法非常麻煩,于是乎一石二鳥,Composition API 即趕上了最新的 API 風(fēng)格,又趕上了最新的語(yǔ)言風(fēng)格。ps:也許是我憑空 yy???
?從個(gè)人的角度來(lái)講,作為 Vue 的使用者,我感覺 Vue3 比 React 要好。因?yàn)?Vue3 是在 React 后推出的,它看到 hooks API 之后才發(fā)明的 Composition API,那它就避免了 React 中的幾個(gè)顯著的問(wèn)題,比如:不能獲取最新的值,手動(dòng)寫依賴不太容易寫好,可能某個(gè)依賴忘寫導(dǎo)致不更新...文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-578316.html
end ??文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-578316.html
到了這里,關(guān)于Vue2 ? Vue3 都做了哪些改變?的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!