淺析vue3中組件的二次封裝
背景
在實際開發(fā)中每個開發(fā)者應該都有經歷過對組件進行二次封裝,在進行封裝的時候需要保留組件已有的功能,這時需要重寫組件方法,當組件已有大量功能時候,則需要重寫很多重復代碼。且組件功能進行修改的時候,封裝的組件也需要對應修改,從而造成許多開發(fā)和維護成本。下面將從三個方面來基于 Element UI 的el-input
組件簡單實現一下組件的二次封裝。
第一方面:屬性綁定
在對組件封裝的時候首先會遇到就是綁定屬性了,簡單說就是將二次封裝的組件屬性綁定到el-input
組件上。 可能有些小伙伴做的時候會將el-input
的屬性全部寫到封裝組件 props 里面,然后再將這些屬性綁定到el-input
組件上。這樣做不是不行,但是太雞肋了,而且浪費時間。那該如何做呢?
在 vue 實例中有一個屬性$attrs,這個屬性包含了組件所有透傳attributes的對象。是指由父組件傳入,且沒有被子組件聲明為 props 或是組件自定義事件的 attributes 和事件處理函數。 那我們就可以直接將$attrs以v-bind動態(tài)綁定到el-input
組件上,就可以解決屬性綁定這方面的問題了。
<template> <el-input ref="refInput" v-bind="$attrs"></el-input> </template> <script> export default { } </script>
第二方面:插槽
第二方面就是插槽的綁定了,可以和屬性綁定一樣,將所有的插槽全部寫出來,然后再一個一個寫到el-input
組件上,如果插槽不多,也沒有什么影響,但是如果插槽很多呢,如果二次封裝的是有可能會修改的組件呢?那這個二次封裝的組件也要同步修改,很麻煩!那又該如何做呢?
我們可以通過另一個屬性$slots,這個屬性表示父組件所傳入插槽的對象。每一個插槽都在$slots上暴露為一個函數,返回一個 vnode 數組,同時 key 名對應著插槽名。 那我們就可以遍歷$slots動態(tài)綁定到el-input
組件上,就可以解決綁定插槽這方面的問題了。
<template> <el-input ref="refInput" v-bind="$attrs"> <template v-for="(value, name) in $slots" #[name]> <slot :name="name" /> </template> </el-input> </template> <script> export default { } </script>
但如果再考慮得深一點,你會發(fā)現有的時候這個組件會向這個插槽傳遞一些數據,就是作用域插槽了。
<template> <el-input ref="refInput" v-bind="$attrs"> <template v-for="(_value, name) in $slots" #[name]="slotData"> <slot :name="name" v-bind="slotData || {}" /> </template> </el-input> </template> <script> export default { } </script>
第三方面: ref
我們使用組件的時候保不齊就會使用ref調用組件里面暴露的方法。我們可以通過這么幾種方式實現:
- 暴露
el-input
的ref,然后通過this.$ref[二次封裝組件的ref][el-input的ref].focus()
的方式調用。 - 在組件內重新寫
el-input
的方法并綁定到el-input
組件上,然后暴露出去。
以上這兩種方式都可以是現實,但是我們實際開發(fā)過程中如果組件被修改了,那所有使用該組件的地方都需要進行調整,而且咱們都不希望寫這么多無聊的代碼。就出現了以下主要介紹方式:
我們換一種思路,我們要做的無非就是將el-input
的方法提取到我們封裝的組件上暴露給使用組件的地方使用。那我們就可以將el-input
的方法通過ref的方式獲取到然后放到封裝組件的實例里面去。
在進行組合式API封裝前先介紹一個屬性expose,用于聲明當組件實例被父組件通過模板引用訪問時暴露的公共屬性。默認情況下,當通過 $parent
、$root
或模板引用訪問時,組件實例將向父組件暴露所有的實例屬性。
選項式
<template> <el-input ref="refInput" v-bind="$attrs"> <template v-for="(_value, name) in $slots" #[name]="slotData"> <slot :name="name" v-bind="slotData || {}" /> </template> </el-input> </template> <script> export default { data() { return {} }, mounted() { const entries = Object.entries(this.$refs.refInput) for(const [key, value] of entries) { this[key] = value } } } </script>
組合式
在組合式setup函數中我們需要先通過getCurrentInstance
方法獲取當前組件實例,然后將提取el-input
組件暴露的方法暴露出去。需要注意的是我們在使用setup方法的時候會在最后將需要使用到的屬性或者方法return
出去使用。但是在setup函數它在beforeCreate之前發(fā)生,所以我們獲取不到el-input
組件的實例,所以就需要在onMounted的時候將el-input
組件暴露的方法加到當前組件實例的expose屬性中,但是沒有主動聲明暴露的時候expose屬性是null
,所以我們需要先主動聲明暴露,在onMounted的時候將el-input
組件暴露的方法添加到expose中。
<template> <el-input ref="refInput" v-bind="$attrs"> <template v-for="(_value, name) in $slots" #[name]="slotData"> <slot :name="name" v-bind="slotData || {}" /> </template> </el-input> </template> <script> import { ref, onMounted, getCurrentInstance } from 'vue' export default { setup(props, context) { const instance = getCurrentInstance() const refInput = ref() onMounted(() => { const entries = Object.entries(refInput.value.$.exposed) for (const [key, value] of entries) { instance.exposed[key] = value } }) context.expose() return { refInput } } } </script>
setup標簽
setup標簽
寫法與組合式封裝方法相似。不同的是在setup標簽
中當前組件實例的expose不為null
,所以不需要主動聲明暴露。
<template> <el-input ref="refInput" v-bind="$attrs"> <template v-for="(_value, name) in $slots" #[name]="slotData"> <slot :name="name" v-bind="slotData || {}" /> </template> </el-input> </template> <script setup> import { ref, onMounted, getCurrentInstance } from 'vue' const instance = getCurrentInstance() const refInput = ref() onMounted(() => { const entries = Object.entries(refInput.value.$.exposed) for (const [key, value] of entries) { instance.exposed[key] = value } }) </script>
附上源碼
到此這篇關于淺析vue3中組件的二次封裝的文章就介紹到這了,更多相關vue3組件封裝內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
詳解探索 vuex 2.0 以及使用 vuejs 2.0 + vuex 2.0 構建記事本應用
本篇文章主要介紹了詳解探索 vuex 2.0 以及使用 vuejs 2.0 + vuex 2.0 構建記事本應用 ,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-06-06