Vue3中ElementPlus组件二次封装,实现原组件属性、插槽、事件监听、方法的透传

11,425次阅读
没有评论

共计 2277 个字符,预计需要花费 6 分钟才能阅读完成。

本文以 el-input 组件为例,其它组件类似用法。
Vue3 中 ElementPlus 组件二次封装,实现原组件属性、插槽、事件监听、方法的透传

一、解决数据绑定问题

封装组件的第一步,要解决的就是数据绑定的问题,由于 prop 数据流是单向传递的,数据只能从父流向子,子想改父只能通过提交 emit 事件通知父修改。
父:

import { ref } from 'vue'
import CInput from '@/components/CInput/index.vue'

const name = refstring>('')
c-input v-model:value="name"/>

子组件:

import { ref, computed } from 'vue';
const props = withDefaults(defineProps{
    value: string;
}>(), {
    value: ''
})
const inputValue = computed({
    get: () => props.value,
    set: (value: string) => emit('update:value', value)
})
el-input
   v-model="inputValue" 
>/el-input>

以上即可实现父子之前数据的双向传递。
但在 Vue3.4+ 版本中,新增了defineModel() ,这个宏可以用来声明一个双向绑定 prop,通过父组件的 v-model 来使用:const model = defineModel()。同样实现了父子组件数据的双向绑定。感兴趣的同学可以看下官网解释,其有更多用法。

二、属性、事件监听

在 vue3 版本中,“透传 attribute”指的是传递给一个组件,却没有被该组件声明为 props 或 emits 的 attribute 或者 v-on 事件监听器。
例如 el-input 组件上有许多属性,clearable、show-word-limit、show-password、@input、@focus 等等,这些肯定不需要通过 props 传递给子组件,那就是通过 $attrs 来进行传递。
在子组件封装时,编写:

el-input 
    v-model="inputValue"
    v-bind="$attrs" 
>
/el-input>

当然对于你二次封装的组件,根据你的业务需要,直接固定一些属性。
这样,在父组件中,我们可以像使用 el-input 组件一样,使用我们自己的组件传递属性和监听事件。

c-input ref="nameRef" class="name-input" v-model:value="addForm.name" @input="handleInput" clearable/>

三、插槽传递

对于 ElementPlus 中的组件,通常都会都一些插槽,那我们封装后想保留这些插槽的使用,该如何写?Vue3 为我们提供了$slots,里面存着父组件所传入插槽的对象。所以我们可以这样写:

el-input 
   ref="input"
   class="c-input" 
   v-model="inputValue" 
   :placeholder="props.label" 
   v-bind="$attrs" 
>
   template v-for="(_, name) in $slots" v-slot:[name]>
       slot :name="name">/slot>
   /template>
/el-input>

这样,在父组件中我们可以正常使用 el-input 中所带有的插槽:

c-input v-model:value="loginForm.account" :label="$t('input.username')" clearable>
   template #prefix>
       el-icon>User />/el-icon>
   /template>
/c-input>

四、原组件方法获取并暴露

最后一步,在父组件中想通过绑定 ref 调用 el-input 的方法,该如何写?首先父组件直接调用肯定是不行的,因为封装的组件中并没有这些方法,这些方法是挂在封装的 el-input 的实例对象上的。所以,解决办法就是我们通过在子组件中获取到这些方法,然后通过 defineExpose 向父组件暴露就行了。
子组件:

import { ref, onMounted, defineExpose } from 'vue';
import type { InputInstance } from 'element-plus';

const input = refInputInstance>()
const inputMethods = ref({})

onMounted(() => {
    const refMethods = Object.entries(input.value).filter(([_, value]) => value instanceof Function)
    refMethods.forEach(([key, value]) => {
        inputMethods.value[key] = value
    })
})
defineExpose(inputMethods.value)

el-input 
   ref="input"
   class="c-input" 
   v-model="inputValue" 
   :placeholder="props.label" 
   v-bind="$attrs" 
>
   template v-for="(_, name) in $slots" v-slot:[name]>
       slot :name="name">/slot>
   /template>
/el-input>

这样,父组件中获取该组件的实例对象上就会存在这些方法了。完美解决!

原文地址: Vue3 中 ElementPlus 组件二次封装,实现原组件属性、插槽、事件监听、方法的透传

    正文完
     0
    Yojack
    版权声明:本篇文章由 Yojack 于2024-10-02发表,共计2277字。
    转载说明:
    1 本网站名称:优杰开发笔记
    2 本站永久网址:https://yojack.cn
    3 本网站的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,请联系站长进行删除处理。
    4 本站一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
    5 本站所有内容均可转载及分享, 但请注明出处
    6 我们始终尊重原创作者的版权,所有文章在发布时,均尽可能注明出处与作者。
    7 站长邮箱:laylwenl@gmail.com
    评论(没有评论)