Сниппеты Vue 3 TypeScript и советы
В этой статье мы собрали коллекцию полезных фрагментов кода и советов, которые часто ищуться в документации Vue. Наличие всех этих сниппетов в одном месте должно облегчить использование их в качестве примеров быстрого копирования и вставки, что в конечном итоге сэкономит драгоценное время при разработке с использованием Vue 3 и TypeScript.
Определение компонента
Вот пример определения компонента с использованием синтаксиса <script setup>
. Макросы defineProps
и defineEmits
используются для объявления компонента prop
и event
соответственно. Помощник withDefaults
позволяет нам устанавливать значения по умолчанию для prop
. Мы можем определить это как пользовательский фрагмент кода в нашем редакторе кода, который будет служить отправной точкой при создании нового компонента.
<template>
<div class="mb-4 flex items-center rounded bg-blue-50 p-4 text-blue-800">
<div class="text-sm font-medium">
{{ text }}
</div>
<button
v-if="closeable"
type="button"
class="-m-1.5 ms-auto inline-flex size-8 items-center justify-center rounded p-1.5 hover:bg-blue-100"
@click="close"
>
✕
</button>
</div>
</template>
<script setup lang="ts">
defineOptions({
name: 'SimpleComponent'
})
type Props = {
text?: string
closeable?: boolean
}
const props = withDefaults(defineProps<Props>(), {
text: '',
closeable: false
})
const emit = defineEmits<{
'click:close': [value: string]
}>()
const close = () => {
emit('click:close', props.text)
}
</script>
Проверка prop
Чтобы проверить prop
, мы должны использовать макрос defineProps
вместе с утилитой PropType
. Это позволяет нам указать тип и валидатор function
, который проверяет значение prop
. Здесь текст проверяется, чтобы убедиться, что он начинался с буквы «Т».
import { type PropType } from 'vue'
defineProps({
text: {
type: String as PropType<string>,
default: 'Test',
validator(value: string) {
return value.startsWith('T')
}
}
})
Определение ссылки на шаблон
Иногда нам нужна ссылка на DOM
элемент внутри нашего шаблона. Мы можем добиться этого, используя ref
.
<template>
<div ref="header" class="text-4xl">Header text</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const header = ref<HTMLElement | null>(null)
</script>
Определение ссылки на компонент (получение типа компонента)
Точно так же, как и в случае со ссылками на элементы DOM
, бывают случаи, когда нам требуется ссылка на компонент в нашем шаблоне. Для этого мы можем использовать утилиту InstanceType
вместе с typeof
. Это гарантирует, что ссылки на наши компоненты введены правильно.
<template>
<SimpleComponent ref="simpleComponentRef" :text="'Hello world!'" />
</template>
<script setup lang="ts">
import SimpleComponent from './SimpleComponent.vue'
import { ref } from 'vue'
type SimpleComponentType = InstanceType<typeof SimpleComponent>
const simpleComponentRef = ref<SimpleComponentType | null>(null)
</script>
В тех случаях, когда точный тип компонента недоступен или не важен, мы можем использовать общий тип компонента ComponentPublicInstance
, который предоставляет нам Vue:
import { type ComponentPublicInstance } from 'vue'
const simpleComponentRef = ref<ComponentPublicInstance | null>(null)
Общий тип компонента
В сценариях, где нам необходимо динамически хранить и отображать компоненты, мы можем использовать универсальный тип Component
. Таким сценарием может быть, например, сохранение компонентов в object
или array
, чтобы мы могли динамически отображать их в шаблоне. Для этого мы можем использовать универсальный тип Component
. Используя shallowRef
, мы гарантируем, что Vue не будет жаловаться на [Vue warn]: Vue received a Component that was made a reactive object.
.
<template>
<Component :is="components.settings" />
</template>
<script setup lang="ts">
import { type Component, shallowRef } from 'vue'
import IconSettings from './IconSettings'
import IconHome from './IconHome'
const components = ref<Record<string, Component>>({})
// Later in our code
components.value.settings= IconSettings
components.value.home = IconHome
</script>
Мы также можем использовать ссылку shallowRef
на один компонент.
const settings = shallowRef(IconSettings)
Простые компоненты обертки с defineModel
Ранее можно было создать оболочку ввода во Vue 3, привязав события вручную. Однако, начиная с Vue 3.4, появился более простой способ добиться этого с помощью defineModel
.
<template>
<div>
<label class="block">
{{ label }}
</label>
<input v-model="model" type="text" class="rounded border p-2" />
</div>
</template>
<script setup lang="ts">
defineOptions({
name: 'InputWrapper'
})
withDefaults(defineProps<{ label?: string }>(), {
label: ''
})
const model = defineModel<string>({ default: '' })
</script>
Работа с отключенным наследованием атрибутов
В Vue 3 прослушиватели событий, а также style
и class
теперь являются частью всех атрибутов. Когда мы работаем с inheritAttrs: false
, нам часто хочется распределить разные атрибуты по разным частям наших компонентов. В следующих примерах мы увидим, как с этим можно справиться.
Получение слушателей, как в Vue 2
Мы по-прежнему можем извлекать прослушиватели событий, используя свойство useAttrs
и computed
.
<template>
<div>
<button type="button" v-bind="listeners">✕</button>
</div>
</template>
<script setup lang="ts">
import { computed, useAttrs } from 'vue'
defineOptions({
inheritAttrs: false
})
const allAttrs = useAttrs()
const listeners = computed(() => {
return Object.keys(allAttrs).reduce((acc, curr) => {
if (curr.startsWith('on')) {
return { ...acc, [curr]: allAttrs[curr] }
} else {
return acc
}
}, {})
})
</script>
Получение всех атрибутов без стилей и классов
Иногда полезно отделить style
и classes
от остальных атрибутов. Мы можем легко сделать это, используя оператор распространения для извлечения их из всех атрибутов.
import { computed, useAttrs } from 'vue'
const allAttrs = useAttrs()
const attrs = computed(() => {
const { class: classes, style, ...rest } = allAttrs
return rest
})
Получение только стиля из attr
Точно так же мы можем извлечь любую часть из всех атрибутов. Вот пример, показывающий, как мы можем извлечь style
.
import { computed, useAttrs } from 'vue'
const allAttrs = useAttrs()
const style = computed(() => {
return allAttrs.style as StyleValue
})
Заключение
Мы надеемся, что эти фрагменты и советы помогут оптимизировать процесс разработки с помощью Vue 3 и TypeScript. Если у вас есть собственные часто используемые фрагменты кода или вы часто забываете, как делать определенные вещи в Vue, поделитесь ими в комментариях.