В статье речь пойдет о низкоуровневой реализации цикла жизни компонента: объявление, монтирование в DOM, дестрой экземпляром компонента самого себя.
Мы привыкли к наиболее частому использованию компонентов: объявление, регистрация, обращение к компоненту из другого с передачей параметров. Описываем компонент в файле componentName.vue и вызываем в шаблоне другого компонента как <component-name /> А как быть если мы хотим вызвать скажем диалоговое окно из плагина? И хотим чтобы о нашем диалоговом окне не знало все приложение, а знал только плагин? Именно с такой задачей столкнулась на рабочем проекте и собирать информацию пришлось по крупицам. Расскажу как было реализовано все перечисленное. Я делала в плагине, но это не обязательно. Этот подход можно реализовывать и в самом проекте.
Среда разработки:
Vue: 2
Nuxt: ^2.15
Vuetify: ^2.6
Глобальная регистрация компонента.
Внутри моего плагина notification регистрирую максимально простой компонент - диалоговое окно с переданным в плагин типом, сообщением и кнопкой закрытия. Тип определяет какого цвета сообщение. Классические: success, info, error, warning. Кнопка закрытия диалогового окна будет дестроить экземпляр компонента и удалять его из DOM. Логики у моего компонента почти не будет - только шаблон. Поэтому в компоненте сразу идет render функция. Ее задача - вернуть html-код компонента.
let Nf = Vue.component('notificationDialog', {
render: function (createElement) {
}
})
По функции есть хорошая документация, не буду останавливаться.
Далее, описываем вложенность html тегов при помощи createElement
const alertVNode = createElement('v-alert', {
attrs: { type: message.type, icon: false }, // атрибуты
style: { // стили элемента
width: '100%'
}
},
message.text) // содержимое: String или Array<VNodes>
const cardVNode = createElement('v-card', {
class: ['pa-2', 'd-flex', 'flex-column', 'align-end',]
},
[alertVNode]) // Предыдущий узел добавляется как дочерний в карточку
Кто заметил что-то необычное, тот молодец. Да! createElement понимает теги Vuetify. Это здорово, т.к. экономит время на написание вложенных тегов и стилей для них! И еще одно. По этой же причине можно менять стили на релевантные им классы. Пример ниже.
const cardDivVNode = createElement('v-card', {
style:{
padding: ‘8px’,
display: ‘flex’,
flexDirection: ‘column’,
alignItems: ‘end’
},
class: ['pa-2', 'd-flex', 'flex-column', 'align-end',]
})
То что вы видите в объектах style и class в примере выше - одно и тоже. То есть padding: ‘8px’ - все равно, что заменить классом ‘pa-2’. Расшифровывается как ‘padding all = 2*4px’. Поэтому, для единообразного дизайна - пользуюсь классами Vuetify там, где это возможно:
const cardDivVNode = createElement('v-card', {
class: ['pa-2', 'd-flex', 'flex-column', 'align-end',]
})
Монтирование экземпляра компонента и добавление в DOM
Компонент объявлен. Далее, в логике плагина мы:
создаем экземпляр класса
монтируем его в DOM
и добавляем как дочерний элемент нашего корневого элемента с id=”app”
let component = new Nf() // создаем экземпляр класса
component.$mount() // монтируем его в DOM
document.getElementById('app')?.appendChild(component.$el) // добавляем в корень
На этом этапе все.
Дестрой экземпляра компонента, удаление из DOM
Как говорила выше, дестроить экземпляр компонента будет сам себя. В шаблоне компонента notificationDialog, в рендер функции присутствует кнопка закрытия диалогового окна:
const closeButtonVNode = createElement('v-btn', {
attrs: {
outlined: true, // аттрибуты Vuetify
color: 'primary',
block: false,
inline: true
},
on: {
// события размещаются тут
}
}, 'Close')
У нее и будет метод onClick:
const closeButtonVNode = createElement('v-btn', {
…
on: {
click: () => {
this.$destroy() // дестроим текущий экземпляр
this.$el?.parentNode?.removeChild(this.$el) // удаляем из DOM
}
}
}, 'Close')
Заключение
У нас получилось создать компонент notificationDialog в плагине, о котором не знает основное приложение.
Компонент объявляется глобально - один раз, при билдинге приложения
Экземпляры создаются при вызове плагина
Экземпляры дестроят сами себя по нажатию на кнопку.
Комментарии (7)
B_bird
17.06.2023 12:39+3Можно сократить. Статья c громким названием нам всего лишь пересказывает (примешивая зачем-то сюда вьютифай) два небольших раздела документации, а именно:
С целью сделать создания компонента as service.
Добро пожаловать в мир вью, вас ждет еще много интересного, если вызывает удивление это:
createElement понимает теги Vuetify
vasyakolobok77
17.06.2023 12:39Некоторые замечания по коду:
new Nf()
Абсолютно неинформативное имя класса / компонента.
style:{ padding: ‘8px’
На слое js безусловно можно управлять оформлением, но лучше выносить это на слой css, и управлять со слоя js только посредством css-классов.
document.getElementById('app')
Жесткая привязка к элементу #app. Может у меня корневой элемент vue назван иначе?
И я не увидел api, которым будет пользоваться прикладной разработчик. Что-то типа showNotification(....). Вы же не хотите обязать каждого создавать руками объекты и монтировать их?
golubeva-webmaster Автор
17.06.2023 12:39>И я не увидел api, которым будет пользоваться прикладной разработчик.
golubeva-webmaster Автор
17.06.2023 12:39Оставила это "за скобками", т.к. это уже про реализацию плагина. Да, стоит добавить способы передачи параметров, тут соглашусь.
Dimava
17.06.2023 12:39Напоминаю, что поддержка Vue2 заканчивается в конце 2023 года
Если собираетесь переезжать на Vue3 - пора
Начинать на Vue2 новые проекты точно не стоит
dopusteam
А откуда 4 взялось?Погуглил, это в verify так решили сделать, оказывается