vue3+ts组件的二次封装,继承式新增和改写属性

2,381 阅读1分钟

有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">
// 这是一个组件A
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" />