Vue 組件如何模塊化抽離Props
一、為什么要抽離Props
在前端框架中封裝一個(gè)組件是非常常見(jiàn)的,對(duì)于組件來(lái)講,往往離不開(kāi)組件之間屬性的傳遞,通過(guò)屬性能夠控制組件的樣式內(nèi)容、處理邏輯類型、數(shù)據(jù)傳遞。假如有這么一個(gè)用于簽名的組件,能夠控制畫(huà)筆的大小、顏色、畫(huà)布背景顏色寬高、按鈕的文案提示等,那么它的屬性必定是有十幾個(gè)選項(xiàng),假設(shè) 800 行代碼里可能就得花費(fèi) 100 行去聲明這些屬性,這明顯是不合適的。
這也是我為什么提議要抽離組件 Props 的原因,實(shí)際上這個(gè)簽名組件也確實(shí)存在,源自于我在 Uniapp 插件市場(chǎng)上的一個(gè)提交。

抽離Props的好處有這么幾點(diǎn):
- 降低、隔離組件的復(fù)雜度,降低維護(hù)成本與提高程序可靠率。
- 引入一個(gè)中間的、易于理解的抽象概覽。
- 隱藏非核心處理部分的實(shí)現(xiàn)細(xì)節(jié),提高組件源碼的可閱讀性。
- 促進(jìn)代碼的重用,包裝一定的結(jié)構(gòu)風(fēng)范。
- 屬性的抽離,有助于自動(dòng)化程序生成對(duì)應(yīng)文檔。
那么要怎么做才能抽離出 Props 呢,在 Vue 身上根據(jù)選項(xiàng)式 API 和組合式 API 寫(xiě)法的不同,做法也不一樣。
一些簡(jiǎn)單的組件可能只有一兩個(gè)屬性,甚至是沒(méi)有屬性,對(duì)于這種情況下,可能不抽離 Props 會(huì)顯得更方便一些,但一定要注意的是應(yīng)當(dāng)把組件以后要做的和其擴(kuò)展維護(hù)性放在一起考慮,往往十幾個(gè)屬性堆疊的組件都是從一兩個(gè)屬性的組件開(kāi)始的,既然以后會(huì)越加越多,那為何不提早抽離處理方便以后再加呢,當(dāng)然具體怎么做取決于自己。
二、選項(xiàng)式API方式抽離
選項(xiàng)式 API 適用于 Vue2 和 Vue3,需要使用到 Mixins 混合方法。Mixins 不只是能抽離 Props,它能做到更多,我相信大部分對(duì)這個(gè)功能會(huì)比較熟悉,有興趣的可以參考此文檔 Mixins。
import type { PropType } from "vue";
export default {
props: {
prop1: {
type: String,
required: true
},
prop2: {
type: Array as PropType<string[]>,
default: ["a", "b", "c"]
},
prop3: {
type: Array as PropType<Record<string, unknown>[]>,
defalue: []
}
}
};<script lang="ts">
import props from "./props";
export default {
mixins: [props]
};
</script>三、組合式API方式抽離
組合式 API 屬性的聲明依賴于 defineProps 編譯宏,這個(gè)編譯宏只能出現(xiàn)在 .vue 的文件中才能正確識(shí)別,那么對(duì)于 Hook 來(lái)說(shuō),抽離 Props 是行不通的。
3.1 TypeScript類型方式
defineProps 是支持 typescript 類型標(biāo)注聲明的,直接引入一個(gè)類型行不行得通的呢?關(guān)于這個(gè)問(wèn)題要分 Vue3.3 版本之前與之后,Vue3.3 版本之前是不允許將類型接口以導(dǎo)入的形式傳給 defineProps 泛型,在官方文檔中也有對(duì)應(yīng)的標(biāo)注,相關(guān)討論在這 issue。


但這還有一個(gè)問(wèn)題,typescript只能聲明類型,如果要配置默認(rèn)值的話需要搭配另外一個(gè)編譯宏 withDefaults 去實(shí)現(xiàn),且類型接口能導(dǎo)入還好,若是不能導(dǎo)入的話,本地類型接口又違背降低復(fù)雜度而抽離的初衷了,在我看來(lái)還不如不用。依據(jù) Vue3.3 版本之后,可以參考下列示例:
export interface Props {
prop1: string;
prop2?: string[];
prop3?: Record<string, unknown>[];
}
export const propsDefault = {
prop1: "默認(rèn)值",
prop2: () => ["a", "b", "c"]
};<template>
<div>{{ $props.prop1 }}</div>
<div>{{ $props.prop2 }}</div>
</template>
<script lang="ts" setup>
import { type Props, propsDefault } from "./props";
const $props = withDefaults(defineProps<Props>(), propsDefault);
</script>3.2 文件分離方式
人們往往容易把簡(jiǎn)單的東西想復(fù)雜,將 Props 類型聲明存放到一個(gè)單獨(dú)文件里,只要確保 defineProps 在 .vue 文件中使用即可,這么做有個(gè)好處就是簡(jiǎn)單易用且在不依賴typescript的時(shí)候基本兼容 Vue3 各版本,對(duì)于我來(lái)講,我更習(xí)慣于使用 文件分離式 進(jìn)行 Props 的抽離。
這種方式與 Hook 不同的是,Hook需要一層函數(shù)包裹執(zhí)行,而這樣相當(dāng)于直接引入配置文件中的一個(gè)變量。
import type { PropType } from "vue";
export const props = {
prop1: {
type: String,
required: true
},
prop2: {
type: Array as PropType<string[]>,
default: ["a", "b", "c"]
},
prop3: {
type: Array as PropType<Record<string, unknown>[]>,
defalue: []
}
};<template>
<div>{{ $props.prop1 }}</div>
<div>{{ $props.prop2 }}</div>
</template>
<script lang="ts" setup>
const $props = defineProps(props);
</script>對(duì)于 TypeScript 如果需要獲取 Props 的類型,那就需要用到 Vue 的一個(gè)輔助類型 ExtractPropTypes,對(duì)于外部引用(父組件)的話使用 ExtractPublicPropTypes,只需在上面示例的基礎(chǔ)上改造一下??。
import type { PropType, ExtractPropTypes } from "vue";
export const props = {
prop1: {
type: String,
required: true
},
prop2: {
type: Array as PropType<string[]>,
default: ["a", "b", "c"]
},
prop3: {
type: Array as PropType<Record<string, unknown>[]>,
defalue: []
}
};
// 導(dǎo)出 Props 類型
export type Props = ExtractPropTypes<typeof props>;其實(shí) ElementUI 的源碼也是這么去做的,以 el-empty 組件為例,源碼中對(duì)于屬性的分離是這么寫(xiě)的。

3.3 對(duì)文件分離方式優(yōu)化
從優(yōu)化的角度上看,Vue 的Props聲明方式都是一樣的,同樣的代碼寫(xiě)多次顯得有些冗余,那不妨將這些 Props 聲明再次優(yōu)化一下,編寫(xiě)一個(gè)公共的 Props 輔助工具進(jìn)行聲明。
"use strict";
/**
* 組件屬性輔助
* ?? 能夠使用更少的代碼編寫(xiě),有助于減少包體積
*/
import type { PropType } from "vue";
export const unknownProp = null as unknown as PropType<unknown>;
export const numericProp = [Number, String];
export const truthProp = {
type: Boolean,
default: true as const
};
export const lieProp = {
type: Boolean,
default: false as const
};
export const makeRequiredProp = <T>(type: T) => {
return { type, required: true as const };
};
export const makeNumericProp = <T>(defVal: T) => {
return { type: numericProp, default: defVal };
};
export const makeStringProp = <T>(defVal: T) => {
return { type: String as unknown as PropType<T>, default: defVal };
};
export const makeNumberProp = <T>(defVal: T) => {
return { type: Number as unknown as PropType<T>, default: defVal };
};
export const makeArrayProp = <T>(defVal: T[]) => {
return { type: Array as PropType<T[]>, default: () => defVal };
};
export const makeObjectProp = <T>(defVal: T) => {
return { type: Object as PropType<T>, default: () => defVal };
};
export const makeFuncProp = <T>(defVal: T) => {
return { type: Function as PropType<T>, default: defVal };
};
// 聯(lián)和類型屬性
export const makeUniteProp = <T, V>(type: T[], defVal: V) => {
return { type, default: () => defVal };
};import type { PropType, ExtractPropTypes } from "vue";
import {makeArrayProp, makeRequiredProp} from "@/utils/props"
export const props = {
prop1: makeRequiredProp(String),
prop2: makeArrayProp<string>(["a", "b", "c"]),
prop3: makeArrayProp<Record<string, unknown>[]>([])
};
export type Props = ExtractPropTypes<typeof props>;參考資料??
官方手冊(cè):
到此這篇關(guān)于Vue 組件如何模塊化抽離Props的文章就介紹到這了,更多相關(guān)Vue 模塊化抽離Props內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
nuxt.js 在middleware(中間件)中實(shí)現(xiàn)路由鑒權(quán)操作
這篇文章主要介紹了nuxt.js 在middleware(中間件)中實(shí)現(xiàn)路由鑒權(quán)操作,具有很好的參考價(jià)值,希望大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-11-11
Vue3封裝hooks實(shí)現(xiàn)實(shí)時(shí)獲取麥克風(fēng)音量
這篇文章主要為大家詳細(xì)介紹了Vue3如何通過(guò)封裝一個(gè)hooks實(shí)現(xiàn)實(shí)時(shí)獲取麥克風(fēng)音量功能,文中的示例代碼講解詳細(xì),需要的小伙伴可以參考一下2024-03-03
使用Vue-scroller頁(yè)面input框不能觸發(fā)滑動(dòng)的問(wèn)題及解決方法
這篇文章主要介紹了使用Vue-scroller頁(yè)面input框不能觸發(fā)滑動(dòng)的問(wèn)題,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08
vue 調(diào)用 RESTful風(fēng)格接口操作
這篇文章主要介紹了vue 調(diào)用 RESTful風(fēng)格接口操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-08-08
vue使用html2PDF實(shí)現(xiàn)將內(nèi)容導(dǎo)出為PDF
將 HTML 轉(zhuǎn)換為 PDF 進(jìn)行下載是一個(gè)比較常見(jiàn)的功能,這篇文章將通過(guò)html2PDF實(shí)現(xiàn)將頁(yè)面內(nèi)容導(dǎo)出為PDF,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-11-11
VUE+SpringBoot實(shí)現(xiàn)分頁(yè)功能
這篇文章主要為大家詳細(xì)介紹了VUE+SpringBoot實(shí)現(xiàn)分頁(yè)功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-06-06

