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

相关推荐
FRing037 小时前
vue2干货总结3(computed计算属性、watch监听器)
开发语言·前端·vue.js·vue2
Java小卷8 小时前
JuanForm vs FormCreate!Vue3 表单引擎联动配置 PK!
vue.js·低代码
小郎君65817 小时前
Vue 多标签页的加载态设计:为什么我没有用 Suspense 实现 PageLoading
vue.js·算法
yilaisai17 小时前
前端开发遇到的一些细节问题整理
vue.js
华玥作者18 小时前
Vue 3 + TypeScript + uni-app 组件库推荐:hy-app(华玥组件库)
vue.js·typescript·uni-app
阿琳a_18 小时前
b-map-viewer:面向 Vue 3 的地图可视化 SDK,从接入到展示再到交互分析
前端·javascript·vue.js·gis·数据可视化·地图
齐 飞19 小时前
VUE2常用语法总结
javascript·vue.js
北城笑笑19 小时前
Vue 106 ,上篇:前端桌面端应用实现方案( Electron 框架详细介绍,Vue + Electron )
前端·javascript·vue.js·python·electron
不磕了还不行20 小时前
用 Vue + Element UI 把元宝搜索的返回值做成“能点开检查的证据卡片”
前端·vue.js·ui
FRing031 天前
vue2干货总结2(v-bind、v-for、v-model、指令修饰符、v-bind操作class和style)
开发语言·前端·vue.js·vue2