DevGang
Авторизоваться

Сниппеты 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, поделитесь ими в комментариях.

Источник:

#JavaScript #TypeScript #Vue.js
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться

Присоединяйся в тусовку

В этом месте могла бы быть ваша реклама

Разместить рекламу