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的函数导出即可

相关推荐
fmdpenny33 分钟前
Vue3初学之商品的增,删,改功能
开发语言·javascript·vue.js
涔溪1 小时前
有哪些常见的 Vue 错误?
前端·javascript·vue.js
亦黑迷失3 小时前
vue 项目优化之函数式组件
前端·vue.js·性能优化
计算机-秋大田4 小时前
基于SpringBoot的高校教师科研的设计与实现(源码+SQL脚本+LW+部署讲解等)
java·vue.js·spring boot·后端·课程设计
eason_fan4 小时前
分析vue3源码23(异步组件实现)
vue.js·前端框架·源码阅读
BigData-06 小时前
vue视频流播放,支持多种视频格式,如rmvb、mkv
前端·javascript·vue.js
工业互联网专业7 小时前
基于springboot+vue的高校社团管理系统的设计与实现
java·vue.js·spring boot·毕业设计·源码·课程设计
白宇横流学长8 小时前
基于SpringBoot+Vue的旅游管理系统【源码+文档+部署讲解】
vue.js·spring boot·旅游
张人玉9 小时前
小白误入(需要一定的vue基础 )使用node建立服务器——vue前端登录注册页面连接到数据库
服务器·前端·vue.js
大大。9 小时前
element el-table合并单元格
前端·javascript·vue.js