descriptive text Hammerbot
descriptive text
typescript
vuejs

L’héritage de composants avec Vue 3

Quand on utilise vue, on aime souvent faire des wrappers autour de composants existants.

Pour faire ça bien, il faut faire suivre principalement 4 choses:

Pour le reste de cet article, on prendra en exemple 2 composants: Wrapped et Wrapper.

Comme son nom l’indique, le Wrapper va envelopper Wrapped et faire suivre tout ce qu’il faut.

Commençons d’abord par voir à quoi ressemble Wrapped, le composant que l’on souhaite envelopper:

<template>
    <div :style="{color: props.color}">
        <div>
            <slot name="header"></slot>
        </div>
        <slot></slot>
        <div>
            <button @click="emit('validate')">Validate</button>
        </div>
    </div>
</template>

<script lang="ts" setup>
const emit = defineEmits<{
    validate: [];
}>();
const props = defineProps<{
    color?: string;
}>()
</script>
html

Comme on peut le voir, ce composant possède 2 slots. Un slot nommé header et le slot par défaut. Il émet un événement validate et accepte une propriété color.

La solution

<template>
  <Wrapped v-bind="{ ...props, ...attrs }" v-on="emit">
    <template v-for="(_, name) in slots" v-slot:[name]="slotData"
      ><slot :name="name" v-bind="slotData"
    /></template>
  </Wrapped>
</template>

<script lang="ts" setup>
import { useAttrs } from "vue";
import type {
  ComponentProps,
  ComponentSlots,
  ComponentEmit
} from "vue-component-type-helpers";

import Wrapped from "./Wrapped.vue";

type Slots = ComponentSlots<typeof Wrapped>;
type Props = ComponentProps<typeof Wrapped>;
type Emit = ComponentEmit<typeof Wrapped>;

const props = defineProps<Props>();
const emit = defineEmits<Emit>();
const slots = defineSlots<Slots>();

const attrs = useAttrs();

</script>
html

Limites

Il existe toutefois des limites à cette solution. On pourrait faire en sorte également de faire suivre les fonctions exposées par les composants. Dîtes moi en commentaire si vous avez besoin de faire suivre ça! ⬇️

Quelques liens intéressants

https://github.com/vuejs/language-tools/blob/master/packages/component-type-helpers/index.ts

https://gist.github.com/loilo/73c55ed04917ecf5d682ec70a2a1b8e2


Chargement des commentaires