有A组件
<template>
<div>
<div>title: {{ title || '没有title' }}</div>
<div v-if="!(options && options.length)">没有内容</div>
<template v-else>
<div v-for="item in options">
<div>label: {{ item.label }}</div>
<div>value: {{ item.value }}</div>
</div>
</template>
</div>
</template>
<script setup lang="ts">
export interface AOption {
label: string
value: string
}
export interface AProps {
options?: AOption[]
title?: string
}
defineProps<AProps>()
</script>
有B组件对A组件进行二次封装,新增和改写属性,无需列出A组件的全部属性
<template>
<div>
<ACom v-bind="targetAttrs" />
<div>foot: {{ foot || '没有foot' }}</div>
</div>
</template>
<script setup lang="ts">
import { computed, useAttrs } from 'vue'
import ACom, { AOption, AProps } from './a.vue'
// 对a组件进行二次封装
// 继承a组件的所有功能
// 新增foot属性
// 并且改写options的数据类型
export interface BProps extends Omit<AProps, 'options'> {
// 新增foot属性
foot?: string
// 把options属性改为可以是函数
// 属性类型改动需要原属性删除相关类型先 Omit<AProps, 'options'>
options?: AOption[] | (() => AOption[])
}
const props = defineProps<BProps>()
const attrs: Partial<AProps> = useAttrs()
function getOptions() {
if (typeof props.options === 'function') {
return props.options() || []
}
if (Array.isArray(props.options)) {
return props.options
}
return []
}
const targetAttrs = computed<AProps>(() => {
return { ...attrs, options: getOptions() }
})
</script>
B组件拥有了A组件所有属性
<BCom :options="() => [{ label: 'xxx', value: 'xxx' }]" title="这里是title" foot="这里是foot" />