vue3继承并扩展三方组件完成二次封装

文章使用naiveui的Input组件进行举例,elementPlus或者其他组件库同理

继承emits和props

xml 复制代码
<!-- TInput.vue -->
<script setup lang="ts">
//导入三方组件提供的props
import { NInput, inputProps } from 'naive-ui'
//定义props
const props = defineProps(inputProps)
//扩展默认组件的type类型
const props = defineProps(inputProps)
</script>
<template>
  <NInput v-bind="props" ref="_ref">
  </NInput>
</template>

这样就能完整的继承组件的props和emits了 在另一个文件中检查一下类型是否正确

很完美

扩展emits和props呢

我们利用assign方法来进行扩展 举个例子,为placeholder添加一个前缀,这是原本输入框的清除按钮

xml 复制代码
<!-- TInput.vue -->
<script setup lang="ts">
//导入三方组件提供的props
import { NInput, inputProps } from 'naive-ui'
import { assign } from 'lodash'
import { computed, onMounted, ref } from 'vue'

//扩展placeholder的前缀
const props = defineProps(
  assign(inputProps, {
    placeholder: {
      type: String,
      default: 'default-input'
    },
    suffix: {
      type: String,
      default: ''
    }
  })
)

const _placeHolder = computed(() => props?.suffix + props?.placeholder)
</script>
<template>
   <NInput v-bind="props" :placeholder="_placeHolder" ref="_ref"> </NInput>
</template>
xml 复制代码
//使用TInput组件
<template>

  <TInput v-model:value="val" :suffix="'suffix'"></TInput>

</template>

可以看到我们对 placeholder设置的前缀生效了

继承插槽

我们可以通过useSlots或者$slots来获取到接受到的插槽,然后只要简单的循环就能继承插槽了

xml 复制代码
<template>
  <NInput v-bind="props" ref="_ref" :placeholder="_placeHolder">
    <template v-for="(_, name) in $slots" #[name]="slotData">
      <slot :name v-bind="slotData || {}"></slot>
    </template>
  </NInput>
</template>

扩展插槽

举个例子,我想修改NInput默认的清除按钮,但又保留使用插槽修改清除按钮的功能 这是原本的清除按钮

现在将这个清除按钮的默认值修改为c 为插槽设置默认值

xml 复制代码
<template>
   <NInput v-bind="props" ref="_ref" :placeholder="_placeHolder">
    <template #clear-icon><div>c</div></template>
    <template v-for="(_, name) in $slots" #[name]="slotData" :key="name">
      <slot :name v-bind="slotData || {}"></slot>
    </template>
  </NInput>
</template>

当我 没有使用clear-icon的插槽的时候,可以看到

当我使用clear-icon的插槽的时候

perl 复制代码
  <TInput v-model:value="val" :suffix="'suffix'" clearable>
    <template #clear-icon>
      <div>q</div>
    </template>
  </TInput>

插槽没有类型提示

需要检查你使用的三方组件是否导出了Slots的类型,然后在defineSlots中使用这个类型,使用类型工具扩展.但是由于组件泛型并不好用.定义slots的类型意义不大. 由于naiveui并没有导出Slots的类型,因此这里不做演示

继承组件实例提供的方法

继承组件实例的方法需要在Mounted的生命周期中,获取组件实例并且将其导出

typescript 复制代码
<template>
  <NInput ref="_ref" >
  </NInput>
</template>
<script setup lang="ts">
const _ref = ref()
const _expose: Record<string, any> = {
  getInst: () => {
    return _ref.value
  }
}
defineExpose(_expose)
</script> 

在使用TInput组件的时候引入组件实例的类型,实现良好的类型提示

typescript 复制代码
<script setup lang="ts">
import TInput from './components/TInput.vue'
import { onMounted, ref } from 'vue'
import { type InputInst } from 'naive-ui'
const val = ref()
const inputRef = ref< { getInst: () => InputInst }>()
onMounted(() => {
  console.log(inputRef.value?.getInst?.()?.focus())
})
</script>
<template>
  <TInput ref="inputRef" v-model:value="val" :suffix="'suffix'" clearable> </TInput>
</template>

注意,不要使用循环的方式为expose添加键值对,因为对组件实例的操作会让vue提交警告, `void app logic that relies on enumerating keys on a component instance. The keys will be empty in production mode to avoid performance overhead. 因此简单的把组件实例通过expose的函数导出即可

相关推荐
devincob2 小时前
js原生、vue导出、react导出、axios ( post请求方式)跨平台导出下载四种方式的demo
javascript·vue.js·react.js
木头没有瓜4 小时前
在 Windows 中清理依赖node_modules并重新安装
vue.js
不吃香菜的猪4 小时前
el-upload实现文件上传预览
前端·javascript·vue.js
dcloud_jibinbin5 小时前
【uniapp】小程序体积优化,分包异步化
前端·vue.js·webpack·性能优化·微信小程序·uni-app
qq_427506085 小时前
基于Vue 3和Element Plus实现简单的钩子函数管理各类弹窗操作
前端·javascript·vue.js
六月的可乐8 小时前
实战干货-Vue实现AI聊天助手全流程解析
前端·vue.js·ai编程
一 乐9 小时前
智慧党建|党务学习|基于SprinBoot+vue的智慧党建学习平台(源码+数据库+文档)
java·前端·数据库·vue.js·spring boot·学习
暴富的Tdy10 小时前
【基于 WangEditor v5 + Vue2 封装 CSDN 风格富文本组件】
vue.js·wangeditor·富文本
开发者小天10 小时前
React中的componentWillUnmount 使用
前端·javascript·vue.js·react.js
永远的个初学者11 小时前
图片优化 上传图片压缩 npm包支持vue(react)框架开源插件 支持在线与本地
前端·vue.js·react.js