Власні директиви - для повторного використання низькорівневої роботи з DOM на звичайних елементах: фокус, перехоплення кліків поза елементом, підказки, виділення тексту, ліниве завантаження.
У <script setup> будь-яка змінна з назвою vЩось стає директивою v-щось:
<script setup>
const vFocus = {
mounted: (el) => el.focus(),
};
</script>
<template>
<input v-focus>
</template>
Повний набір хуків (усі необов'язкові):
const vClickOutside = {
mounted(el, binding) {
el._onClick = (event) => {
if (!el.contains(event.target)) binding.value(event);
};
document.addEventListener('click', el._onClick);
},
unmounted(el) {
document.removeEventListener('click', el._onClick);
},
};
<div v-click-outside="closeMenu">...</div>
Хуки: created, beforeMount, mounted, beforeUpdate, updated, beforeUnmount, unmounted. Аргумент binding містить value, oldValue, arg (v-tooltip:top → 'top') і modifiers (v-tooltip.delay → { delay: true }).
Скорочена форма - функція замість об'єкта: викликається в mounted і updated.
Глобальна реєстрація - app.directive('focus', vFocus).
Коли директива - правильний вибір, а коли ні:
- так: логіка прив'язана до конкретного DOM-елемента й не має власного шаблону чи складного стану;
- ні - краще компонент: є розмітка (підказка з вмістом, випадне меню);
- ні - краще composable: логіка зі станом, яку зручно використати в
setup(useClickOutside(target, handler),useIntersectionObserver). Composable краще типізується й тестується; - ні - краще вбудовані директиви: документація радить декларативні
v-bind,v-showтам, де можливо, - вони ефективніші й дружні до SSR.
Пастки:
- на компонентах директиви не рекомендовані: застосовуються до кореневого елемента, а на компоненті з кількома коренями ігноруються з попередженням (на відміну від атрибутів, їх не передати через
$attrs); - аргументи хуків - лише для читання, крім
el. Спільні дані між хуками - черезel.datasetчиWeakMap, а не довільні властивості на елементі (якel._onClickу прикладі - працює, але це компроміс); - прибирання в
unmountedобов'язкове для глобальних слухачів і спостерігачів; - SSR: хуки директив на сервері не викликаються (крім
getSSRPropsдля атрибутів).