|
В шаблонах Vue используют предопределенные директивы [1], управляющие отображением страницы. Но также у пользователя есть возможность создать собственные директивы.
Пользовательская директива Vue это по сути определяемый объект JavaScript, котором есть возможность привязаться к жизненным циклам элемента, для которого директива предназначена.
Имя объекта для директивы должно начинаться на букву v, например:
< script setup> import { ref, onMounted } from 'vue'
... const vFocus = { mounted: (el) => el.focus()
};
< /script>
Тогда в шаблоне эта директива будет доступна под именем v-focus.
Пользовательские директивы Vue представляют собой инструмент для повторного использования логики низкоуровневого доступа к DOM (Document Object Model), который применяется, когда декларативных возможностей компонентов и composables недостаточно.
Ниже — структурированный обзор того, как они работают в Vue 3 (с ключевыми отличиями от Vue 2).
[1. Назначение и когда использовать]
Не путать с компонентами: директивы не заменяют бизнес-логику, они работают напрямую с DOM-элементами.
Когда нужны:
- Автофокус (el.focus()). - Интеграция сторонних библиотек (drag & drop, кастомные скроллбары). - Манипуляции с атрибутами/стилями при появлении элемента. - Ленивая загрузка изображений (IntersectionObserver). - UI-фичи: закрепление элемента (`v-pin`).
Когда НЕ нужны:
- Вся бизнес-логика, работа с API, хранилища (Pinia/Vuex) — это задача компонентов или composables.
[2. Структура и жизненные хуки (Vue 3)]
Директива — это объект с хуками, аналогичными хукам компонента. Все хуки опциональны.
| hook |
Момент вызова |
| created |
До применения атрибутов/слушателей |
| beforeMount |
Перед вставкой элемента в DOM |
| mounted |
Элемент в DOM (самый частый хук) |
| beforeUpdate |
Перед обновлением родителя |
| updated |
После обновления родителя и детей |
| beforeUnmount |
Перед удалением элемента |
| unmounted |
Элемент удалён из DOM (чистим слушатели) |
Vue 2 vs Vue 3 — названия хуков изменились:
- bind → mounted - inserted → удалён - update → updated - componentUpdated → удалён - unbind → unmounted
[3. Аргументы хуков (объект binding)]
В каждый хук приходит 4 аргумента:
mounted(el, binding, vnode, prevVnode)
Объект binding — самое важное:
{ value: // переданное значение (v-dir="1" → 1) oldValue: // предыдущее (только update/updated) arg: // аргумент (v-dir:foo → 'foo') modifiers: // модификаторы (v-dir.once → { once: true }) instance: // экземпляр компонента dir: // объект самой директивы
}
Динамический аргумент — реактивно обновляется:
< div v-pin:[direction]="200">< /div> < !-- direction может меняться -->
[4. Создание и регистрация]
Локально (в компоненте):
Composition API (< script setup>) — автоматически, если переменная с префиксом `v`:
< script setup> const vFocus = { mounted: (el) => el.focus() }
< /script>
< template>
< input v-focus />
< /template>
Options API — через опцию `directives`:
export default { directives: { focus: { mounted: (el) => el.focus() } }
}
Глобально:
import { createApp } from 'vue' const app = createApp(App)
app.directive('focus', { mounted: (el) => el.focus() })
Доступна во всех компонентах без импорта.
[5. Синтаксический сахар]
Если логика одинакова для mounted и updated, то директива может быть функцией:
app.directive('color', (el, binding) => { el.style.color = binding.value
})
Передача объекта параметров:
< div v-demo="{ color: 'white', text: 'hello' }">< /div>
[6. Особенности работы с компонентами]
- На однокорневом компоненте — директива применяется к корневому узлу. - На многокорневом (fragment) — игнорируется, будет warning. - Нельзя прокинуть через v-bind="$attrs" (в отличие от атрибутов).
Не рекомендуется использовать пользовательские директивы на компонентах.
[7. Практические примеры из реальной разработки]
| Сценарий |
Суть реализации |
| Автофокус с задержкой |
setTimeout(() => el.focus(), binding.value || 0) |
| Ленивая загрузка |
IntersectionObserver → подмена el.src |
| Закрепление (pin) |
el.style.position = fixed, top/left из binding.arg |
| Кнопка по ролям |
el.disabled = true если роль не совпадает |
[8. Best Practices]
1. Чистота: директива — только DOM. API, сторы, вычисления — в компонент. 2. Очистка: если навесили addEventListener в mounted — снимите в unmounted. 3. Простота: если директива сложнее 10 строк — возможно нужен компонент. 4. Не злоупотреблять: встроенные v-bind, v-show, v-if почти всегда лучше кастомных. 5. Чтение: объект binding (кроме el) — readonly. Обмен данными между хуками — через el.dataset.
Если вы переходите с Vue 2: самое важное изменение — имена хуков и отказ от синтаксиса "одной функции по умолчанию". Vue 3 предлагает чёткий объект с именованными методами жизненного цикла.
[Ссылки]
1. Директивы шаблона Vue. |