Низкоуровневая реализация полного цикла жизни компонента во Vue 2

от автора

В статье речь пойдет о низкоуровневой реализации цикла жизни компонента: объявление, монтирование в 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 в плагине, о котором не знает основное приложение. 

  • Компонент объявляется глобально — один раз, при билдинге приложения

  • Экземпляры создаются при вызове плагина

  • Экземпляры дестроят сами себя по нажатию на кнопку.


ссылка на оригинал статьи https://habr.com/ru/articles/742310/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *