Vue3.3發(fā)布了,有啥新特性?簡(jiǎn)單的了解下

前言
雖然3.3當(dāng)前還處于beta階段但是其帶來(lái)的一些特性十分激動(dòng)人心,就在這里簡(jiǎn)單的給大家?guī)?lái)新特性的前瞻,為以后的升級(jí)做做準(zhǔn)備??
泛型組件支持
Vue一直以來(lái)[1]都是沒(méi)辦法很好的實(shí)現(xiàn)泛型組件,終于在3.3版本增加了這一功能
首先是面向TSX用戶為defineComponent?工具函數(shù)增加了泛型支持,當(dāng)參數(shù)傳入一個(gè)泛型函數(shù)時(shí)類型會(huì)提示正常,比如我們可以基于這個(gè)特性使用tsx簡(jiǎn)單構(gòu)造一個(gè)表格組件
import { defineComponent } from 'vue';
type Props<T> = { data: T[]; columns: { label: string; field: keyof T }[] };
const Table = defineComponent(<T,>(props: Props<T>) => {
return () => (
<table>
<thead>
<tr>
{props.columns?.map((item) => (
<th>{item.label}th>
))}
tr>
thead>
<tbody>
{props.data?.map((row) =>
props.columns?.map((column) => <td>{row[column.field]}td>)
)}
tbody>
table>
);
});
export default Object.assign(Table, {
name: 'GenericsTableTsx',
props: ['columns', 'data']
});
但是值得注意的是我們?nèi)孕枰獮檫@個(gè)組件傳入props屬性,否則在使用的時(shí)候會(huì)將應(yīng)該是props的的屬性掛載到$attrs上,這點(diǎn)其實(shí)基本上杜絕了這樣的用法,所以說(shuō)僅僅只是類型正確,不太推薦生產(chǎn)用這樣的方法構(gòu)建泛型組件。
SFC泛型組件支持
其實(shí)上面的功能還是為了鋪墊這個(gè),我們了解怎么用SFC來(lái)復(fù)現(xiàn)上面的組件
<template>
<table>
<thead>
<tr>
<th v-for="item in columns">
<slot name="header-cell" v-bind="{ label: item.label }">
{{ item.label }}
slot>
th>
tr>
thead>
<tbody>
<tr v-for="row in data">
<td v-for="column in columns">
<slot name="cell" v-bind="{ data: row[column.field] }">
{{ row[column.field] }}
slot>
td>
tr>
tbody>
table>
template>
<script setup lang="ts" generic="T">
const { columns, data } = defineProps<{
data: T[];
columns: {
label: string;
field: keyof T;
}[];
}>();
script>
[email protected]為script增加了一個(gè)屬性generic用于創(chuàng)建泛型參數(shù),多個(gè)參數(shù)當(dāng)然也像是ts中使用,隔開(kāi)。
評(píng)價(jià): 很強(qiáng)的新特性,vue終于有泛型組件了真的是可喜可賀,就是對(duì)于TSX的支持還是需要額外增加props屬性比較麻煩,這個(gè)問(wèn)題也是比較久遠(yuǎn)的了,希望vue團(tuán)隊(duì)以后在為T(mén)SX的開(kāi)發(fā)體驗(yàn)提升上努努力
defineProps 宏支持引入的類型
這個(gè)需求[2]已經(jīng)2年過(guò)去了,不過(guò)大部分開(kāi)發(fā)者都有使用一些社區(qū)插件來(lái)達(dá)到這個(gè)用法,現(xiàn)在官方終于提供了,在3.3我們可以輕松的使用外部導(dǎo)入的類型創(chuàng)建Props
<script setup lang="ts">
import type { SomeType } from 'some-where'
const props = defineProps<{ data: SomeType }>()
script>
評(píng)價(jià): 眾望所歸,更方便的管理在Vue項(xiàng)目中的類型,不需要再在SFC中寫(xiě)又臭又長(zhǎng)的類型體操了
defineEmits 宏更簡(jiǎn)便的寫(xiě)法
對(duì)于3.2,defineEmits基于泛型需要這樣使用
defineEmits<{
(e: 'foo', id: string): void
(e: 'bar',...args: any[]): void
}>()
3.3的寫(xiě)法,對(duì)于單個(gè)參數(shù)使用具名元組的方式定義,如果使用rest params的參數(shù)可以直接使用T[]來(lái)解決
defineEmits<{
foo: [id: string]
bar: any[]
}>()
評(píng)價(jià): 提升DX的小功能,函數(shù)重載的形式寫(xiě)起太多的emits確實(shí)有點(diǎn)煩人
為v-model帶來(lái)新的工具
這是來(lái)自智子君[3]的新特性[4],可以在中使用defineModel和非中使用的useModel工具
// 默認(rèn)的model (通過(guò) `v-model`)
const modelValue = defineModel()
// ^? Ref
modelValue.value = 10
const modelValue = defineModel<string>() //增加類型
// ^? Ref
modelValue.value = "hello"
// 帶有設(shè)置的默認(rèn)model, 要求非undefined
const modelValue = defineModel<string>({ required: true })
// ^? Ref
// 特定名稱的model (通過(guò) `v-model:count` )
const count = defineModel('count')
count.value++
// 具有默認(rèn)值的特定名稱的model
const count = defineModel('count', { default: 0 })
// ^? Ref
// 本地作用域可變的 model, 顧名思義
// 可以不需要父組件傳遞v-model
const count = defineModel('count', { local: true, default: 0 })
還有useModel作為非中使用的工具
import { useModel } from 'vue'
export default {
props: {
modelValue: { type: Number, default: 0 },
},
emits: ['update:modelValue'],
setup(props) {
const modelValue = useModel(props, 'modelValue')
// ^? Ref
return { modelValue }
}
}
評(píng)價(jià): 又一提升DX的利器,定義一個(gè)
v-model的屬性確實(shí)比較繁瑣,而且在sfc內(nèi)實(shí)用性不強(qiáng),一般需要搭配`vueuse/useVModels`[5]使用,官方加入這個(gè)宏和工具函數(shù)確實(shí)是很不錯(cuò)
defineOptions
又是智子君的pr,早前來(lái)自RFC[6],這個(gè)內(nèi)容的話應(yīng)該不少人都在Vue Macro中用過(guò)了
本來(lái)Vue如果你需要在中定義一些原先Option Api的屬性比如inheritAttrs/name是需要?jiǎng)?chuàng)建一個(gè)單獨(dú)導(dǎo)出這兩個(gè)屬性的,現(xiàn)在有了defineOptions就可以省去這一步驟
<script setup>
// 一些代碼
script>
<script>
export default {
name: "ComponentName"
}
script>
<script setup>
defineOptions({
name: "ComponentName"
})
// 一些代碼
script>
評(píng)價(jià): 這個(gè)特性可以在`Vue Macro`[7]使用到,先行體驗(yàn),反正我是用上了很爽
defineSlots 宏以及 slots 屬性
還是來(lái)自智子君[8],TQL
允許定義slots的具體類型,首先是新增了一個(gè)SlotsType以及slots屬性可以options api中使用
import { SlotsType } from 'vue'
export default defineComponent({
slots: Object as SlotsType<{
default: { foo: string; bar: number }
item: { data: number }
}>,
setup(props, { slots }) {
expectType<undefined | ((scope: { foo: string; bar: number }) => any)>(
slots.default
)
expectType<undefined | ((scope: { data: number }) => any)>(slots.item)
}
})
對(duì)于這個(gè)定義的組件SlotComponent,再組件中使用的話就是
<template>
<SlotComponent>
<template #default="{ foo, bar }">
{{ foo }} is string,{{ bar }} is number
template>
<template #item="{ data }">
{{ data }} is number
template>
SlotComponent>
template>
defineSlots和slots屬性類似,不過(guò)提供一個(gè)函數(shù)語(yǔ)法
// 與 對(duì)象語(yǔ)法表現(xiàn)一致,謝謝ES沒(méi)有將default當(dāng)屬性關(guān)鍵詞 可喜可賀可喜可賀??
const slots = defineSlots<{
default(props: { foo: string; bar: number }): any // or VNode[]
}>()
評(píng)價(jià): slot有正確的類型的話對(duì)于組件庫(kù)來(lái)說(shuō)是一個(gè)挺好的消息,畢竟從引入
scopeSlot到現(xiàn)在用戶都不能很好地確定自己該怎么用某個(gè)scopeSlot
模板中使用 console.log
突然的調(diào)試可能會(huì)用到的console.log但是在模板中不好使,現(xiàn)在3.3加上了額外支持,不需要再自己為模板作用域增加一個(gè)函數(shù)來(lái)打印東西了
評(píng)價(jià): 無(wú)傷大雅,提升DX,偶爾會(huì)用到會(huì)感覺(jué)很舒服
不太重要的特性
對(duì)Suspense的改進(jìn)
個(gè)人覺(jué)得vue的可以暫時(shí)不用關(guān)注,實(shí)驗(yàn)性特性好久了,pr在這里[9]
廢棄和修改的特性
v-is 指令廢棄
廢棄v-is了,全部改用:is指令(好奇真的有人還在用這個(gè)指令嗎?)
app.config.unwrapInjectedRef
app.config.unwrapInjectedRef這個(gè)屬性沒(méi)了,在3.3會(huì)默認(rèn)對(duì)使用Option api的inject屬性進(jìn)行注入的ref進(jìn)行拆包,
vnode hook 廢棄
vnode hook 應(yīng)該用戶比較少,就是有一個(gè)@vnode-*的指令變成了@vue:*,這個(gè)特性應(yīng)該蠻少用的,甚至連網(wǎng)上都沒(méi)有什么介紹,好像是為Vnode的生命周期提供一些類似與組件生命周期的功能,不知道有沒(méi)有清楚這個(gè)特性能干嗎的伙伴介紹下。
對(duì)于生態(tài)開(kāi)發(fā)者的改進(jìn)
app.runWithContext()
在App上增加了一個(gè)runWithContext()可以用于確保對(duì)應(yīng)用程序級(jí)別的全局變量存在,比如通過(guò)provide的各個(gè)值,可以用于改進(jìn)vue生態(tài)的各個(gè)包,pinia/vue-router之類的
const app = createApp(App)
app.provide('foo', 1)
app.runWithContext(() => inject('foo')) // should return 1
hasInjectionContext
hasInjectionContext這是面向居于vue的庫(kù)作者用于檢查是否可以使用inject()的工具,如果當(dāng)前環(huán)境可以使用就返回true,不可以的環(huán)境其實(shí)就是setup外了,庫(kù)作者使用該函數(shù)可以省去額外對(duì)當(dāng)前環(huán)境的檢測(cè)。
評(píng)價(jià): 這些對(duì)生態(tài)開(kāi)發(fā)者來(lái)說(shuō)比較有用的功能,如果有寫(xiě)庫(kù)的小伙伴可以注意一下
需要注意的
對(duì)于TSX用戶,vue3.3不在默認(rèn)注冊(cè)全局JSX命名空間,需要手動(dòng)在tsconfig.json中修改jsxImportSource[10]或者使用魔法注釋/* @jsxImportSource vue */這是避免全局jsx類型沖突。
作者:enptisulin
鏈接:https://juejin.cn/post/7226619773375152187
來(lái)源:稀土掘金
