Пользовательские директивы Vue: как создать и применять
TL;DR
Пользовательские директивы Vue дают низкоуровневый доступ к DOM и позволяют переиспользовать поведение между компонентами. В этой статье объясняю структуру директив, показываю локальную и глобальную регистрацию, примеры реализации (включая короткую форму) и даю практические чеклисты, критерии приёмки и рекомендации по отладке.
Что такое директива Vue и зачем она нужна
Директивы — это конструкции, которые подсказывают компилятору и рантайму, как обрабатывать атрибуты в шаблоне. В Vue директивы расширяют поведение HTML-элементов в шаблонах и позволяют напрямую взаимодействовать с DOM.
Короткое определение: директива — это привязка к элементу, управляющая его поведением на уровне DOM.
Примеры задач, которые решают директивы:
- добавление слушателей событий;
- манипуляция стилями и атрибутами напрямую;
- интеграция с библиотеками, которые работают с DOM;
- оптимизация производительности в специфичных случаях, когда компонент — избыточное решение.
Важно: директивы не заменяют компоненты и не должны содержать бизнес-логику приложения. Пользуйтесь ими, когда нужен прямой доступ к DOM или повторяемое низкоуровневое поведение.
Структура директив Vue
Директивы Vue помечаются префиксом v- чтобы отличать их от обычных HTML-атрибутов. Префикс говорит компилятору Vue, что атрибут — директива и её поведение нужно применить к элементу.
Пример использования встроенной директивы v-show:
Hello Vue
Кроме v-show, Vue предоставляет v-bind, v-if, v-on и другие готовые директивы для привязки данных, условного рендеринга и обработки событий.
Определение пользовательских директив
Вы можете создать собственные директивы, если нужно переиспользуемое поведение для элементов. Процесс состоит из двух шагов: регистрация (локальная или глобальная) и определение поведения через хуки жизненного цикла директивы.
Регистрация директив
Директиву можно регистрировать локально внутри компонента или глобально для всего приложения. Чаще регистрируют глобально, когда поведение нужно в разных местах приложения. Локальную регистрацию выбирают для простых или одноразовых сценариев.
Пример локальной регистрации (внутри компонента):
Learn about custom directives
В этом примере директива определена как объект в camelCase (changeColor), но в шаблоне её пишут через дефис v-changecolor.
Пример глобальной регистрации (main.js):
// main.js
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
app.directive('changecolor', {
mounted(el, binding, vnode) {
}
})
app.mount('#app')app.directive регистрирует директиву в глобальной области видимости приложения.
Поведение директивы через хуки
Директивы определяют поведение через хуки жизненного цикла: created, mounted, updated и другие. Хуки получают ссылку на элемент (el), объект binding и виртуальный узел vnode.
Пример объекта с хуками:
const directiveObject = {
mounted(el, binding, vnode) {
},
updated(el, binding, vnode) {
}
}
app.directive('changecolor', directiveObject)Если поведение одинаково для mounted и updated, часто удобнее определить директиву как функцию (shorthand). В этом случае функция будет вызываться при монтировании и обновлении:
app.directive('changecolor', (el, binding, vnode) => {
const message = 'Are you sure you want to change the color?'
el.addEventListener('click', () => {
if (confirm(message)) {
el.style.color = binding.value
|| "#" + Math.random().toString().slice(2, 8);
}
})
})В этом примере директива изменяет цвет элемента по клику. Параметры функции:
- el — реальный DOM-элемент, к которому привязана директива;
- binding — объект с информацией о привязке (включая binding.value);
- vnode — виртуальный узел Vue.
Пример тестового компонента
Hello Vue
Learn custom directives
Can't Wait to Get Started {{ name }}
Результат: элемент h2 получает цвет red из binding.value, h3 — случайный цвет при клике. Скриншоты ниже показывают состояние до и после подтверждения.

Когда не стоит использовать директивы
- Когда задачу можно решить декларативно через компонент.
- Когда логика сложная и зависит от состояния приложения — лучше использовать композицию и слоты.
- Для отображения UI, завязанного на reactive-потоках, компонент читабельнее и тестируемее.
Пример плохого применения: реализация сложного виджета с внутренним состоянием через директиву. В этом случае компоненты читаются и поддерживаются легче.
Альтернативные подходы
- Компоненты — для визуальных/функциональных блоков с собственным состоянием.
- Composition API — для повторно используемой логики без доступа к DOM.
- Плагины — для глобальной функциональности без привязки к конкретным элементам.
Выбор: если нужен доступ к DOM — директива; если нужна UI-логика и рендер — компонент.
Практические шаблоны и хорошая практика
- Всегда удаляйте слушатели событий в хуке перед размонтированием (unmounted), чтобы избежать утечек памяти.
- Не храните сложное состояние внутри директивы. Пусть директива выполняет одну очевидную задачу.
- Документируйте API директивы: какие аргументы и значения binding.value ожидаются.
- Используйте имена в стиле kebab-case в шаблоне и camelCase в коде, если регистрируете локально.
Пример с отпиской слушателя:
app.directive('safe-click', {
mounted(el, binding) {
const handler = () => binding.value && binding.value()
el.__safeClickHandler__ = handler
el.addEventListener('click', handler)
},
unmounted(el) {
el.removeEventListener('click', el.__safeClickHandler__)
delete el.__safeClickHandler__
}
})В этом шаблоне мы сохраняем ссылку на обработчик в свойстве DOM-элемента, чтобы корректно отписаться при unmounted.
Чеклист перед релизом (для разработчика и ревьюера)
- Директива покрыта краткой документацией.
- Есть тесты, симулирующие жизненный цикл (mount/update/unmount).
- Отписка от событий реализована.
- Нет побочного состояния внутри директивы.
- Публичный API (binding.value, аргументы) понятен и стабилен.
- Производительность — нет частых пересозданий слушателей.
Критерии приёмки
- Директива выполняет заявленную задачу на всех целевых браузерах.
- Нет утечек памяти при множественном создании/удалении элементов.
- Поведение согласовано с документацией (пример использования и edge-case описаны).
- Наличие unit/e2e теста, проверяющего мажорные сценарии.
Runbook: отладка и откат
- Симптом: элемент перестал реагировать на директиву. Шаги:
- Проверьте регистрацию директивы (глобальная vs локальная).
- Убедитесь, что в mounted происходит добавление слушателей.
- Проверьте, не перезаписано ли свойство el.handler где-то ещё.
- Воспроизведите проблему в минимальном компоненте.
- Откат: замените использование директивы на временный компонент-обёртку для изоляции проблемы.
Тестовые случаи/Acceptance
- Простой сценарий: элемент с binding.value = ‘red’ меняет цвет на red после подтверждения.
- Сценарий без value: элемент получает случайный цвет и его цвет меняется.
- Повторное монтирование: несколько элементов используют директиву — отсутствие пересечений между элементами.
- Удаление элемента: отсутствуют ошибки в консоли, слушатели удалены.
Decision flowchart
flowchart TD
A[Нужен доступ к DOM?] -->|Да| B[Должно ли поведение быть переиспользуемым?]
A -->|Нет| C[Используйте компонент или Composition API]
B -->|Да| D[Создайте директиву]
B -->|Нет| C
D --> E[Регистрация: глобально или локально?]
E -->|Глобально| F[app.directive'...']
E -->|Локально| G[Определить в компоненте]Ментальные модели и эмпирические правила
- «Директива = локальная трансформация элемента». Если задача касается структуры UI или состояний — выберите компонент.
- Минимализм: одна директива — одна ответственность.
- Безопасность: предполагаем, что любая директива может работать с внешними библиотеками, поэтому проверяйте входные данные и используйте защитные проверки.
Совместимость и миграция
- Vue 3 и Composition API — текущая рекомендация для новых приложений. Директивы совместимы с Vue 3, но API регистрации отличается от Vue 2.
- При миграции с Vue 2 на Vue 3: проверьте хуки (могут отличаться имена и порядок вызовов) и способ регистрации глобальных директив.
Безопасность и конфиденциальность
- Директивы, которые вставляют HTML или работают с внешними данными, должны очищать вход (sanitize) и избегать вставки неподготовленного HTML.
- Не храните чувствительные данные в свойствах DOM-элемента.
Краткий план внедрения (Playbook)
- Описать цель директивы и API (binding.value, аргументы).
- Сделать минимальную реализацию (mounted).
- Добавить обработку обновлений (updated) при необходимости.
- Реализовать очистку ресурсов (unmounted).
- Написать unit-тесты и интеграционные тесты.
- Добавить документацию и примеры использования.
- Развернуть и мониторить метрики ошибок.
Глоссарий (1 строка)
- binding — объект, содержащий value, arg, modifiers для текущей привязки;
- vnode — виртуальный узел Vue, содержащий метаданные компонента;
- mounted/updated/unmounted — хуки жизненного цикла директивы.
Итог
Пользовательские директивы Vue — мощный инструмент для управления поведением отдельных элементов и интеграции с низкоуровневыми API браузера. Используйте их, когда нужен прямой доступ к DOM и при этом сохраняйте простоту и читабельность. Всегда документируйте API директивы, очищайте ресурсы и добавляйте тесты.
Похожие материалы
Как обновить прошивку Microsoft Surface
Как собрать портативный MP3‑плеер на DFPlayer
Как извлечь максимум из поездки на работу
Как изучать новый subreddit: подробное руководство