Vue.js предоставляет богатый набор директив для упрощения работы разработчиков. Помимо встроенных директив, Vue.js также поддерживает директивы Custom, которые позволяют разработчикам расширять библиотеку директив Vue.js в соответствии со своими потребностями. Vue.js 3.x имеет некоторые улучшения в директиве Custom по сравнению с Vue.js 2.x. В этой статье рассказывается, как использовать директиву Custom в Vue.js 3.x.
❓ Что такое пользовательская директива?
1. Введение
В Vue.js директивы — это специальные свойства с префиксом v-
. Что он делает, так это немедленно выполняет некоторое действие, когда элемент, к которому он привязан, вставляется в DOM. В Vue.js есть много встроенных директив, например:
v-model
: создает двунаправленную привязку данных к элементам формы;v-show
: переключает отображение свойства CSS элемента на основе значенияtrue
илиfalse
выражения;v-if
: визуализирует или уничтожает элемент на основеtrue
илиfalse
значения выражения;v-for
: отображает список на основе массива.
Эти директивы позволяют нам более декларативно манипулировать DOM, скрывая сложную логику манипулирования DOM. Помимо встроенных директив, Vue.js также позволяет нам зарегистрировать Пользовательскую директиву. Пользовательская директива позволяет нам применять настраиваемое поведение к визуализируемым элементам DOM.
2. Основное использование
Возьмем для примера директиву Global Custom, она регистрируется глобальным методом app.directive(name, options)
и применяется в шаблоне с префиксом v-
. Метод directive()
принимает два параметра.
name
: название директивы, например.focus
;options
: объект конфигурации директивы, который содержит функцию-ловушку для директивы.
Ниже приведен пример пользовательской директивы v-focus
, которая создается путем предварительного создания директивы v-focus
:
const app = createApp({}); app.directive("focus", { // When the bound element is inserted into the DOM ...... mounted(el) { // Focusing elements el.focus(); }, });
Затем используйте в шаблоне:
<input v-focus />
Когда поле ввода монтируется в DOM, оно автоматически получает фокус.
Объект определения директивы может предоставлять несколько функций ловушек (все необязательные):
const myDirective = { // called before bound element's attributes // or event listeners are applied created(el, binding, vnode, prevVnode) { // see below for details on arguments }, // called right before the element is inserted into the DOM. beforeMount(el, binding, vnode, prevVnode) {}, // called when the bound element's parent component // and all its children are mounted. mounted(el, binding, vnode, prevVnode) {}, // called before the parent component is updated beforeUpdate(el, binding, vnode, prevVnode) {}, // called after the parent component and // all of its children have updated updated(el, binding, vnode, prevVnode) {}, // called before the parent component is unmounted beforeUnmount(el, binding, vnode, prevVnode) {}, // called when the parent component is unmounted unmounted(el, binding, vnode, prevVnode) {}, };
Перехватчикам директив передаются следующие аргументы:
el
: элемент, к которому привязана директива. Это можно использовать для прямого управления DOM.binding
:Объект, содержащий атрибутыvalue
,oldValue
,arg
,modifiers
,instance
иdir
.vnode
: базовый VNode, представляющий связанный элемент.prevNode
: VNode, представляющий связанный элемент из предыдущего рендеринга. Доступно только в крюкахbeforeUpdate
иupdated
.
Подробное описание параметров см. в документе Аргументы хука.
🗂️ Классификация
1. Классификация по способу регистрации Директивы
Пользовательские директивы можно классифицировать по методу регистрации: глобальные директивы и локальные директивы.
- Глобальная директива
Глобально зарегистрированные директивы могут использоваться в любом компоненте приложения и обычно регистрируются в экземпляре Vue app
через directive()
:
const app = createApp({}); app.directive("focus", { // When the bound element is inserted into the DOM ...... mounted(el) { // Focusing elements el.focus(); }, });
- Локальная директива
Локально зарегистрированные директивы можно использовать только в компоненте, с которым они зарегистрированы в объекте конфигурации компонента:
const Component = defineComponent({ directives: { focus: { mounted(el) { el.focus(); }, }, }, render() { const { directives } = this.$options; return [withDirectives(h("input"), [[directives.focus]])]; }, });
2. Классификация по методу реализации Директивы
Пользовательскую директиву можно классифицировать по методу реализации: директива объекта и директива функции.
- Директива объекта
Object Directive реализованы как объекты и предоставляют дополнительные опции и методы жизненного цикла:
const app = createApp({}); app.directive("focus", { // When the bound element is inserted into the DOM ...... mounted(el) { // Focusing elements el.focus(); }, });
В исходном коде внутри определения типа интерфейса:
export interface ObjectDirective<T = any, V = any> { created?: DirectiveHook<T, null, V>; beforeMount?: DirectiveHook<T, null, V>; mounted?: DirectiveHook<T, null, V>; beforeUpdate?: DirectiveHook<T, VNode<any, T>, V>; updated?: DirectiveHook<T, VNode<any, T>, V>; beforeUnmount?: DirectiveHook<T, null, V>; unmounted?: DirectiveHook<T, null, V>; getSSRProps?: SSRDirectiveHook; }
- Директива о функциях
Директива Function — это упрощенная форма директивы Object, которая проще в использовании и подходит для сценариев, в которых необходимо выполнить всего несколько операций.
Обычно такое же поведение нужно только для mounted
и updated
, но другие хуки не нужны. В этом случае директива может быть определена непосредственно с помощью функции:
app.directive("color", (el, binding) => { // This will be called on both `mounted` and `updated` el.style.color = binding.value; });
В исходном коде внутри определения типа интерфейса:
export type FunctionDirective<T = any, V = any> = DirectiveHook<T, any, V>; export type DirectiveHook<T = any, Prev = VNode<any, T> | null, V = any> = ( el: T, binding: DirectiveBinding<V>, vnode: VNode<any, T>, prevVNode: Prev ) => void;
⚠️ Советы и рекомендации
При использовании пользовательских D-директив необходимо помнить о ряде проблем:
1. Когда директива принимает несколько аргументов, передайте литерал объекта JS
<div v-demo="{ color: 'white', text: 'hello!' }"></div> app.directive("demo", (el, binding) => { console.log(binding.value.color); // => "white" console.log(binding.value.text); // => "hello!" });
2. Не рекомендуется использовать пользовательские директивы D для компонентов.
Поскольку компонент может содержать несколько корневых узлов, в отличие от attribute
, директива не может быть передана другому элементу через v-bind="$attrs"
.
<MyComponent v-demo="test" /> <!-- template of MyComponent --> <div> <!-- v-demo directive will be applied here --> <span>My component content</span> </div>
3. Второй параметр директивы Custom поддерживает конфигурацию объекта
При определении директивы первый аргумент принимает объект, который содержит функцию ловушки директивы в дополнение к имени директивы, которое отличается от Vue2 и требует внимания.
app.directive("focus", { mounted(el) { el.focus(); }, });
4. Перехватчики команд вызываются несколько раз для элементов, отображаемых v-for
<ul> <li v-for="item in list" v-focus> </ul>
Функция ловушки директивы focus
вызывается несколько раз с каждым элементом li
в качестве аргумента.
5. Модификатор v-on
.native
больше не поддерживается
Редактор выдает предупреждение «'.native' modifier on 'v-on' directive is deprecated.
»
<!-- will generate a warning, the .native modifier is deprecated --> <input @click.native="doSomething" />
Используйте @click
непосредственно в Vue3 для прослушивания нативных событий.
💡 Примеры использования
Ниже приведены 3 примера использования:
v-превью
Реализуйте предварительный просмотр изображения с помощью директивы v-preview
Custom.
Реализация директивы:
export default { mounted(el) { el.addEventListener("mouseenter", (e) => { const img = e.target; const src = img.src; const parent = img.closest(".img-preview-container"); parent.style.position = "relative"; const preview = document.createElement("div"); preview.style.position = "absolute"; preview.style.top = 0; preview.style.left = 0; preview.style.background = "url(" + src + ") no-repeat center center"; preview.style.backgroundSize = "contain"; preview.style.width = "100%"; preview.style.height = "100%"; parent.append(preview); }); el.addEventListener("mouseleave", (e) => { const parent = e.target.closest(".img-preview-container"); parent.style.position = ""; const preview = parent.querySelector("div"); preview.remove(); }); }, };
Регистрация Пользовательская директива:
import { createApp } from "vue"; import vPreview from "./directives/vPreview"; import App from "./App.vue"; const app = createApp(App); app.directive("preview", vPreview); app.mount("#app");
Используйте пользовательскую директиву:
<div class="img-preview-container"> <img v-for="src in imgSrcs" :src="src" v-preview /> </div>
При наведении курсора на элемент img
отображается предварительный просмотр соответствующего изображения в соответствии с его src
. При перемещении мыши предварительный просмотр изображения исчезает. Эта директива v-preview
Custom позволяет нам быстро реализовать интерактивный эффект предварительного просмотра изображения.
Директива показывает и скрывает предварительный просмотр изображения, прослушивая события mouseenter
и mouseleave
, и использует метод closest
для получения родительского контейнера элемента img
и добавления к нему изображения предварительного просмотра.
2. v-верхний регистр
Директива v-uppercase
Custom включает автоматическое преобразование текста в верхний регистр.
Реализация директивы:
export default { created(el, binding) { el.innerHTML = binding.value.toUpperCase(); }, update(el, binding) { el.innerHTML = binding.value.toUpperCase(); }, };
Регистрация Пользовательская директива:
import { createApp } from "vue"; import vUppercase from "./directives/vUppercase"; import App from "./App.vue"; const app = createApp(App); app.directive("uppercase", vUppercase); app.mount("#app");
Используйте пользовательскую директиву:
<p v-uppercase>hello</p>
На странице отображается текст «HELLO». Директива v-uppercase
Custom вызывает метод toUpperCase()
в хуках created
и update
для преобразования текста в верхний регистр и обновления innerHTML
.
3. v-изменить размер
Директива v-resize
Custom позволяет прослушивать изменения ширины окна и выполнять методы обратного вызова.
Реализация директивы:
export default { mounted(el, binding) { const callback = binding.value; window.addEventListener("resize", () => { callback(el.offsetWidth); }); }, };
Регистрация Пользовательская директива:
import { createApp } from "vue"; import vResize from "./directives/vResize"; import App from "./App.vue"; const app = createApp(App); app.directive("resize", vResize); app.mount("#app");
Используйте пользовательскую директиву:
<script setup lang="ts"> const onResize = (width) => { console.log(width); }; </script> <template> <div v-resize="onResize">Width</div> </template>
Директива v-resize
Custom вызывает связанную функцию обратного вызова при изменении размера окна и передает значение offsetWidth
элемента. В методе onResize
мы можем соответственно обработать новую ширину width
элемента, например:
- корректировка стиля
- вызвать API для повторной выборки данных
- изменить порядок страниц и т. д.
Эти директивы относительно просты, но очень широко используются в реальных проектах.
v-scroll
директива события прокрутки;v-mouseenter
/v-mouseleave
директивы событий входа/выхода мыши;v-longpress
директива длинного нажатия;
Это может быть очень полезно для упрощения нашего кода и повышения эффективности разработки.
🖌️ Как использовать в рендере функцию
1. Введение
Чтобы использовать директиву Custom в функции рендеринга Vue3, вам нужно использовать функцию withDirectives()
, которая имеет следующую сигнатуру функции:
function withDirectives( vnode: VNode, // Elements that need to be bound with custom instructions directives: DirectiveArguments ): VNode; // Custom array of directives, array form: [directive, value, argument, modifiers] // The tail element of the array can be omitted if not needed. type DirectiveArguments = Array< | [Directive] | [Directive, any] | [Directive, any, string] | [Directive, any, string, DirectiveModifiers] >;
Используйте пользовательскую директиву:
import { h, withDirectives } from "vue"; // A Custom directive const pin = { mounted() { /* ... */ }, updated() { /* ... */ }, }; // <div v-pin:top.animate="200"></div> const vnode = withDirectives(h("div"), [[pin, 200, "top", { animate: true }]]);
2. Примеры использования
Возьмите в качестве примера директиву v-focus
Custom, вы можете реализовать ее следующим образом:
Импорт функций директивы withDirectives
и Custom:
import { withDirectives } from "vue"; import { focus } from "./directives";
Используйте функцию withDirectives()
в функции рендеринга и передайте аргументы по порядку:
const vnode = h("input", { type: "text", modelValue: "example", onInput: (event) => { // ... }, }); const app = { render() { return withDirectives(vnode, [[focus, true]]); }, };
vnode
в этом примере кода — это виртуальный узел для элемента input
, focus
— это функция директивы v-focus
Custom, а true
— это массив параметров, переданных в директиву Custom для указания автоматического фокуса после того, как элемент вставлен в документ.
📚 Резюме
В этой статье представлены основы использования директивы Custom в Vue.js 3.x, включая определение и регистрацию пользовательских функций директив, параметров в функциях директив и функций-ловушек. Пользовательские директивы — очень важное расширение среды Vue.js, позволяющее разработчикам настраивать директивы для упрощения и повышения эффективности разработки в соответствии со своими потребностями.
Я надеюсь, что эта статья поможет вам изучить директиву Vue.js Custom.
📖 Учебные материалы
Вот некоторые учебные материалы, которые я лично считаю подходящими для директивы Vue3 Custom:
Официальная документация Vue.js — лучший учебник для изучения директивы Vue.js Custom, включая аспекты определений пользовательских директив, регистрации и функций подключения, а также некоторые примеры реальных приложений.
2. Vue Mastery: пользовательская директива Vue 3
Vue Mastery — отличная образовательная онлайн-платформа для Vue.js, а их курс Vue 3 Custom directive — отличный ресурс для изучения того, как использовать и практиковать Custom directive в Vue.js 3.x.
3. Директивы Vue 3: подробное подробное руководство
Эта статья начинается с основ директив, знакомит с использованием встроенных и пользовательских директив в Vue.js, а также иллюстрирует роль и использование директив с помощью практических сценариев применения и примеров.
Если вам нравится изучать JavaScript, вы можете подписаться на меня в Medium или Twitter, чтобы узнать больше о JavaScript!
Дополнительные материалы на PlainEnglish.io.
Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Подпишитесь на нас в Twitter, LinkedIn, YouTube и Discord .