淺析vue3中組件的二次封裝
背景
在實(shí)際開發(fā)中每個(gè)開發(fā)者應(yīng)該都有經(jīng)歷過對(duì)組件進(jìn)行二次封裝,在進(jìn)行封裝的時(shí)候需要保留組件已有的功能,這時(shí)需要重寫組件方法,當(dāng)組件已有大量功能時(shí)候,則需要重寫很多重復(fù)代碼。且組件功能進(jìn)行修改的時(shí)候,封裝的組件也需要對(duì)應(yīng)修改,從而造成許多開發(fā)和維護(hù)成本。下面將從三個(gè)方面來基于 Element UI 的el-input組件簡(jiǎn)單實(shí)現(xiàn)一下組件的二次封裝。
第一方面:屬性綁定
在對(duì)組件封裝的時(shí)候首先會(huì)遇到就是綁定屬性了,簡(jiǎn)單說就是將二次封裝的組件屬性綁定到el-input組件上。 可能有些小伙伴做的時(shí)候會(huì)將el-input的屬性全部寫到封裝組件 props 里面,然后再將這些屬性綁定到el-input組件上。這樣做不是不行,但是太雞肋了,而且浪費(fèi)時(shí)間。那該如何做呢?
在 vue 實(shí)例中有一個(gè)屬性$attrs,這個(gè)屬性包含了組件所有透?jìng)鱝ttributes的對(duì)象。是指由父組件傳入,且沒有被子組件聲明為 props 或是組件自定義事件的 attributes 和事件處理函數(shù)。 那我們就可以直接將$attrs以v-bind動(dòng)態(tài)綁定到el-input組件上,就可以解決屬性綁定這方面的問題了。
<template>
<el-input ref="refInput" v-bind="$attrs"></el-input>
</template>
<script>
export default {
}
</script>第二方面:插槽
第二方面就是插槽的綁定了,可以和屬性綁定一樣,將所有的插槽全部寫出來,然后再一個(gè)一個(gè)寫到el-input組件上,如果插槽不多,也沒有什么影響,但是如果插槽很多呢,如果二次封裝的是有可能會(huì)修改的組件呢?那這個(gè)二次封裝的組件也要同步修改,很麻煩!那又該如何做呢?
我們可以通過另一個(gè)屬性$slots,這個(gè)屬性表示父組件所傳入插槽的對(duì)象。每一個(gè)插槽都在$slots上暴露為一個(gè)函數(shù),返回一個(gè) vnode 數(shù)組,同時(shí) key 名對(duì)應(yīng)著插槽名。 那我們就可以遍歷$slots動(dòng)態(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>但如果再考慮得深一點(diǎn),你會(huì)發(fā)現(xiàn)有的時(shí)候這個(gè)組件會(huì)向這個(gè)插槽傳遞一些數(shù)據(jù),就是作用域插槽了。
<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
我們使用組件的時(shí)候保不齊就會(huì)使用ref調(diào)用組件里面暴露的方法。我們可以通過這么幾種方式實(shí)現(xiàn):
- 暴露
el-input的ref,然后通過this.$ref[二次封裝組件的ref][el-input的ref].focus()的方式調(diào)用。 - 在組件內(nèi)重新寫
el-input的方法并綁定到el-input組件上,然后暴露出去。
以上這兩種方式都可以是現(xiàn)實(shí),但是我們實(shí)際開發(fā)過程中如果組件被修改了,那所有使用該組件的地方都需要進(jìn)行調(diào)整,而且咱們都不希望寫這么多無聊的代碼。就出現(xiàn)了以下主要介紹方式:
我們換一種思路,我們要做的無非就是將el-input的方法提取到我們封裝的組件上暴露給使用組件的地方使用。那我們就可以將el-input的方法通過ref的方式獲取到然后放到封裝組件的實(shí)例里面去。
在進(jìn)行組合式API封裝前先介紹一個(gè)屬性expose,用于聲明當(dāng)組件實(shí)例被父組件通過模板引用訪問時(shí)暴露的公共屬性。默認(rèn)情況下,當(dāng)通過 $parent、$root 或模板引用訪問時(shí),組件實(shí)例將向父組件暴露所有的實(shí)例屬性。
選項(xiàng)式
<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函數(shù)中我們需要先通過getCurrentInstance方法獲取當(dāng)前組件實(shí)例,然后將提取el-input組件暴露的方法暴露出去。需要注意的是我們?cè)谑褂胹etup方法的時(shí)候會(huì)在最后將需要使用到的屬性或者方法return出去使用。但是在setup函數(shù)它在beforeCreate之前發(fā)生,所以我們獲取不到el-input組件的實(shí)例,所以就需要在onMounted的時(shí)候?qū)?code>el-input組件暴露的方法加到當(dāng)前組件實(shí)例的expose屬性中,但是沒有主動(dòng)聲明暴露的時(shí)候expose屬性是null,所以我們需要先主動(dòng)聲明暴露,在onMounted的時(shí)候?qū)?code>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標(biāo)簽
setup標(biāo)簽寫法與組合式封裝方法相似。不同的是在setup標(biāo)簽中當(dāng)前組件實(shí)例的expose不為null,所以不需要主動(dòng)聲明暴露。
<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>附上源碼
到此這篇關(guān)于淺析vue3中組件的二次封裝的文章就介紹到這了,更多相關(guān)vue3組件封裝內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解探索 vuex 2.0 以及使用 vuejs 2.0 + vuex 2.0 構(gòu)建記事本應(yīng)用
本篇文章主要介紹了詳解探索 vuex 2.0 以及使用 vuejs 2.0 + vuex 2.0 構(gòu)建記事本應(yīng)用 ,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06
vue進(jìn)行圖片的預(yù)加載watch用法實(shí)例講解
下面小編就為大家分享一篇vue進(jìn)行圖片的預(yù)加載watch用法實(shí)例講解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-02-02
十個(gè)有用的自定義Vue鉤子函數(shù)總結(jié)
這篇文章主要為大家介紹了十個(gè)Vue.js中有用的自定義鉤子,讓我們的代碼更加好看。文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2022-04-04
Vue.js上下滾動(dòng)加載組件的實(shí)例代碼
本篇文章主要介紹了Vue.js上下滾動(dòng)加載組件的實(shí)例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-07-07

