Какие директивы есть во Vue и как написать свою?
Вопрос
Какие встроенные директивы есть во Vue, чем они отличаются друг от друга и как написать собственную директиву?
Короткий ответ
Директивы — это специальные атрибуты с префиксом v-, которые применяют реактивное поведение к DOM-элементу: v-if/v-show управляют видимостью, v-for рендерит списки, v-bind привязывает атрибуты, v-on — обработчики событий, v-model — двустороннюю привязку. Кастомная директива пишется как объект с хуками жизненного цикла (mounted, updated и т.д.) для прямой работы с DOM-элементом.
Подробный ответ
Встроенные директивы:
v-if/v-else-if/v-else— условный рендеринг: элемент полностью добавляется или удаляется из DOM. Подходит, когда условие меняется редко, т.к. переключение дороже.v-show— переключает CSS-свойствоdisplay: none, элемент остаётся в DOM всегда. Дешевле при частом переключении, но дороже при первом рендере (элемент рендерится в любом случае).v-for— рендерит список по массиву/объекту/диапазону:v-for="item in items" :key="item.id". Директиву всегда нужно сопровождать:key— уникальным идентификатором — чтобы Vue мог эффективно и корректно переиспользовать DOM-узлы при изменении списка.v-bind(:) — реактивно привязывает атрибут/проп/класс/стиль к выражению::src="url",:class="{ active }}",:disabled="isLoading".v-on(@) — навешивает обработчик события:@click="handleClick", поддерживает модификаторы (@click.stop,@submit.prevent).v-model— двусторонняя привязка на форменных элементах и компонентах (см. отдельный вопрос о формах).
Когда встроенных директив не хватает, можно написать кастомную директиву — объект с хуками, повторяющими жизненный цикл компонента: created, beforeMount, mounted, beforeUpdate, updated, beforeUnmount, unmounted. Каждый хук получает сам DOM-элемент (el) и объект binding со значением выражения (binding.value), аргументом (binding.arg) и модификаторами (binding.modifiers). Кастомные директивы нужны, когда требуется прямой императивный доступ к DOM-элементу — фокус, автосайзинг, интеграция со сторонней библиотекой, отслеживание клика вне элемента и т.п. — то, что нельзя выразить декларативно через шаблон.
Пример
<!-- директива v-focus: автофокус на элементе при монтировании -->
<script setup>
const vFocus = {
mounted: (el) => el.focus()
}
</script>
<template>
<input v-focus placeholder="Автофокус при появлении" />
</template>
Директива с параметром и модификатором — подсветка фона по значению и аргументу:
// directives/highlight.js
export const vHighlight = {
mounted(el, binding) {
// binding.value — переданное значение, binding.arg — v-highlight:color
el.style.backgroundColor = binding.value || 'yellow'
},
updated(el, binding) {
el.style.backgroundColor = binding.value || 'yellow'
}
}
<script setup>
import { ref } from 'vue'
import { vHighlight } from './directives/highlight'
const color = ref('lightgreen')
</script>
<template>
<p v-highlight="color">Текст с реактивной подсветкой фона</p>
</template>
Дополнительные вопросы
- Почему
v-forтребует:key, и что произойдёт при его отсутствии или использовании индекса массива в качестве ключа? - В каком случае лучше выбрать
v-show, а в какомv-if? - Можно ли использовать
v-ifиv-forна одном элементе, и почему так делать не рекомендуется?