基于Vue3實(shí)現(xiàn)組件封裝的技巧分享
需求
需求背景
日常開發(fā)中,我們經(jīng)常會使用一些UI組件庫諸如and design vue
、element plus
等輔助開發(fā),提升效率。有時我們需要進(jìn)行個性化封裝,以滿 足在項(xiàng)目中大量使用的需求。
錯誤示范
基于a-modal
封裝一個自定義Modal組件:修改modal樣式
,按鈕樣式
、每次關(guān)閉后銷毀
、渲染到指定元素上
等等,后續(xù)項(xiàng)目的彈窗全部基于該自定義組件。
<template> <div ref="myModal" class="custom-modal"></div> <a-modal v-model:visible="visible" centered destroyOnClose :getContainer="() => $refs.myModal" @ok="handleOk" @cancel="handleCancel" :style="{ width: '560px', ...style }" :cancelText="cancelText" :okText="okText" > <!-- 以上皆為該組件的默認(rèn)屬性 --> <slot></slot> </a-modal> </template> <script setup> const props = defineProps({ title: { type: String, default: "", }, style: { type: Object, default: () => ({}), }, cancelText: { type: String, default: "取消", }, okText: { type: String, default: "確定", }, }); const emits = defineEmits(["handleOk", "handleCancel"]); const visible = ref(false); const handleOk = () => { emits("handleOk"); }; const handleCancel = () => { emits("handleCancel"); }; defineExpose({ visible }); </script> <style lang="less" scoped> .custom-modal { :deep(.ant-modal) { //省略幾百行樣式代碼 } } </style>
代碼封裝完成,于是乎我們便能在項(xiàng)目中應(yīng)用帶有項(xiàng)目風(fēng)格的彈窗
$attrs
問題來了:一切看起來都挺正常。直到有一天同事說:我想要去掉右上角的關(guān)閉按鈕,能改成自定義的嗎
簡單,直接加!
<!-- 省略不相關(guān)代碼 --> <a-modal :closable="closable"></a-modal> <script setup> const props = defineProps({ //... closable:{ type: Boolean, default: false } }); </script>
另一位同事說:我不想讓它是居中的,能改成自定義的嗎
,還有一位同事說…
思考:這樣的情況多了,就有點(diǎn)難頂。每次一有新的需求,我就得改這個組件,導(dǎo)致這個組件代碼越來越冗余。那么是否有一種方式能夠?qū)鬟M(jìn)來的屬性自動綁定給a-modal呢,有,那兒就是attrs
注意:
1.vue提供了$attrs這么一個屬性用于接收父組件傳遞下來的屬性,$attrs不包括已經(jīng)寫入props的值
2.如果父組件傳遞了style,class,那么這這些值不僅會存在于$attrs,還會默認(rèn)綁定至根元素上。這一點(diǎn)需要注意
<modalTest :footer="null" :centered="false" :zIndex="999" /> //此時的$attrs { "footer": null, "centered": false, "zIndex": 999 }
有了這個組件實(shí)例,結(jié)合v-bind
我們就可以這么寫
<a-modal v-model:visible="visible" centered destroyOnClose :getContainer="() => $refs.myModal" :style="{ width: '560px', ...style }" v-bind="$attrs" > <!-- 略 --> </a-modal>
這樣一來,我們就可以使用a-modal
提供的任意屬性和方法了
$slots
問題來了:插槽怎么辦,例如a-modal
就提供了許多插槽,是不是要用哪個就先在自定義組件上寫好呢?
錯誤示例
<a-modal> <!-- default --> <slot></slot> <!-- title --> <template #title> <slot name="title">{{ title }}</slot> </template> <!-- other --> </a-modal>
弊端就像之前的,如果該原生提供了許多插槽,當(dāng)有需要時豈不是頻繁去修改自定義組件添加相應(yīng)的插槽,其實(shí)利用$slots
可以解決這個問題
官網(wǎng)的這段話簡明扼要的說出的插槽的原理,我們所傳遞的插槽最終都是變成
{ 'slotName':fn(...args) //fn返回一個虛擬DOM 'defautl': fn(...args) //默認(rèn)插槽 }
也就是我們傳什么插槽進(jìn)來,$slots
就有什么值那么我們可以遍歷$slots
中的值,有什么插槽我們便動態(tài)綁定什么插槽
<a-modal> <template v-for="(_val, name) in $slots" #[name]="options"> <slot :name="name" v-bind="options || {}"> </slot> </template> </a-modal>
#[name]="options",我們可以拿到原生a-modal在name這個插槽中傳遞來的一些狀態(tài)options,并綁定在<slot>上。詳情請查看官網(wǎng):作用域插槽。
這樣一來,我們原生a-modal
怎么使用插槽,自定義組件就怎么使用插槽
<CustomModal> <template #title="{arg1, arg2}"> content </template> </CustomModal>
至此,封裝的代碼如下
<template> <div ref="myModal" class="custom-modal"></div> <a-modal v-model:visible="visible" centered :getContainer="() => $refs.myModal" :style="{ width: '560px'}" destroyOnClose v-bind="$attrs" > <template v-for="(_val, name) in $slots" #[name]="ops"> <slot :name="name" v-bind="ops || {}"> </slot> </template> </a-modal> </template> <script setup> const visible = ref(false); defineExpose({ visible }); </script> <style lang="less" scoped> .custom-modal { //style } </style>
還有許多優(yōu)化的空間,例如當(dāng)前父組件顯隱該Modal
需使用ref
的方式訪問visible
。在vue3中也可以參考官網(wǎng)的做法這樣子寫
<template> <div ref="myModal" class="custom-modal"></div> <a-modal :visible="visible" //.... v-bind="$attrs" > <!-- ... --> </a-modal> </template> <script setup> defineProps(['visible']) const emit = defineEmits(); // 不用寫"update:visible",vue會自動加上 watch( () => props.visible, (newVal) => emit("update:visible", newVal); ); </script>
那么使用這個控制這個組件的顯示隱藏就方便許多了
<CustomModal v-model:visible="visible"></CustomModal>
本文中的封裝方式是基于vue3來進(jìn)行實(shí)現(xiàn),不局限在什么UI組件身上。如果使用的是vue2,情況稍有不同,請自行了解。
以上就是基于Vue3實(shí)現(xiàn)組件封裝的技巧分享的詳細(xì)內(nèi)容,更多關(guān)于Vue3組件封裝的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
使用idea創(chuàng)建第一個Vue項(xiàng)目
最近在學(xué)習(xí)vue,本文主要介紹了使用idea創(chuàng)建第一個Vue項(xiàng)目,文中根據(jù)圖文介紹的十分詳盡,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-03-03VantUI封裝自定義Tabbar路由跳轉(zhuǎn)的實(shí)現(xiàn)
本文主要介紹了VantUI封裝自定義Tabbar路由跳轉(zhuǎn)的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05解決electron打包vue-element-admin項(xiàng)目頁面無法跳轉(zhuǎn)的問題小結(jié)
這篇文章主要介紹了解決electron打包vue-element-admin項(xiàng)目頁面無法跳轉(zhuǎn)的問題小結(jié),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2024-03-03Vue實(shí)現(xiàn)模糊查詢-Mysql數(shù)據(jù)庫數(shù)據(jù)
這篇文章主要介紹了基于Vue實(shí)現(xiàn)Mysql數(shù)據(jù)庫數(shù)據(jù)模糊查詢,下面文章我們主要實(shí)現(xiàn)的是輸入框中輸入數(shù)據(jù),根據(jù)輸入的結(jié)果模糊搜索數(shù)據(jù)庫對應(yīng)內(nèi)容,實(shí)現(xiàn)模糊查詢,感興趣的小伙伴可以進(jìn)入文章我們一起學(xué)習(xí)2021-12-12如何封裝了一個vue移動端下拉加載下一頁數(shù)據(jù)的組件
這篇文章主要介紹了如何封裝了一個vue移動端下拉加載下一頁數(shù)據(jù)的組件,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-01-01詳解mpvue中小程序自定義導(dǎo)航組件開發(fā)指南
這篇筆記主要記錄一下基于mpvue的小程序中實(shí)現(xiàn)自定義導(dǎo)航的思路及應(yīng)用。小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-02-02詳解如何使用Object.defineProperty實(shí)現(xiàn)簡易的vue功能
這篇文章主要為大家介紹了如何使用Object.defineProperty實(shí)現(xiàn)簡易的vue功能示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04