Задать вопрос
ReturnMeVoid
@ReturnMeVoid

Как правильно писать компоненты-обёртки во Vue 3?

Допустим у меня есть компонент из ui библиотеки - LibModal. Я хочу написать ему обёртку - MyModal.

Я определяю нужные в MyModal пропсы. Но мне нужно, чтобы MyModal принимал не только свои пропсы, но и пропсы LibModal (т.к. это его обёртка). И в таком случае у меня два варианта:

1) В defineProps компонента MyModal указать только новые (нужные обёртке) пропсы. В этом случае, все пропсы для LibModal (не указанные в MyModal, но принимаемые LibModal) можно будет передать в MyModal и они попадут в attrs (и присвоить их ). Этот вариант не подходит, так как не проверяет на типы передаваемые пропсы для LibModal, т.к. они не указаны в defineProps компонента MyModal. Также нет автокомплита из-за этого.

2) В defineProps компонента MyModal помимо его пропсов продублировать пропсы LibModal. В таком случае в пропсы для LibModal уже попадут не в attrs, а в основные пропсы. Но становится не понятно, как оптимально разделить общие пропсы на libModalProps и пропсы для MyModal (и сделать ).

Расскажите, как обычно вы пишете компоненты-обёртки над другими компонентами и как прокидываете их пропсы. Насколько я понял, первый вариант самый распространённый, но отсутствие типизации очень удручает в TS-проекте.

Спасибо за ответы!
  • Вопрос задан
  • 127 просмотров
Подписаться 1 Простой Комментировать
Пригласить эксперта
Ответы на вопрос 2
@null_object
Сначала надо чтобы компонент помимо своих типов наследовал типы дочернего компонента, тут понятно - либо extends, либо через пересечение типов или любой другой способ.
interface MyModalProps extends LibModalProps {
  isOpen: boolean;
}

Поскольку у родительского компонента будут и свои пропсы и дочернего, нужно их разделить и делегировать дочернему только его пропсы, сделать это можно разными способами, например в computed
const delegatedProps = computed(() => {
  // перечисляем пропсы родителя, остальные достаем через spread
  const { isOpen, ...libModalProps } = props;

  return libModalProps;
});

и передаем все пропсы в дочерний компонент
<LibModal v-bind="delegatedProps">
    ...
</LibModal>


Еще вариант использовать reactiveOmit

пример
пример с reactiveOmit из shadcn-ui
Ответ написан
Fragster
@Fragster
помогло? отметь решением!
Вот так работает (на примере quasar):

<template>
  <q-btn
    ref="btnRef"
    :text-color
    v-bind="parentProps"
    @click="onBtnClick"
  />
</template>


<script setup lang="ts">
import type {QBtnProps} from 'quasar'

type PropsType = QBtnProps & {
  textColor?: string,
}
const {textColor = 'black', ...parentProps} = defineProps<PropsType>()

const emit = defineEmits(['click'])
function onBtnClick() {
  console.log('Button clicked')
  emit('click')
}
</script>



либо с использованием https://github.com/vuejs/language-tools/blob/maste...
import {QBtn} from 'quasar'
import type { ComponentProps } from 'vue-component-type-helpers';

type PropsType = ComponentProps<typeof QBtn>  & {
  textColor?: string,
}
const {textColor = 'black', ...parentProps} = defineProps<PropsType>()

UPD: это не компилируется, хотя в VS code все подсказки работают (
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы