Если вы какое-то время являетесь разработчиком, вы знаете ценность повторного использования элементов, которые вы создали ранее. Например, каждый раз, когда вы определяете свойства круга с заданным радиусом и цветом, вы можете написать что-то вроде этого

circle1.radius = 10;
circle1.color = 'red'; 
circle2.radius = 3;
circle2.color = 'blue';

Но ради чистоты кода создание функции было бы более традиционным.

circle1.update(10, ‘red'); 
circle2.update(3, ‘blue);

Мы можем объяснить веб-компоненты как решение для повторного использования пользовательского интерфейса. Возможно, вы знакомы с такими фреймворками, как React, Angular и т. д.. который позволяет создавать повторно используемые компоненты. Когда я впервые начал разрабатывать Front-end, я полностью игнорировал возможности ванильного JavaScript и изучал React и Angular, как будто это был единственный способ справиться с этим. Однако чистый, старый, хороший JavaScript поддерживает эту функцию, не требуя никакой другой платформы или библиотеки.

В этой истории мы увидим, как создавать веб-компоненты и прикреплять их к HTML, используя только JavaScript.

Начиная с файлов

Во-первых, мне нужно добавить файлы index.html и index.js в мой репозиторий. Мы можем начать со стандартного содержимого HTML5 и прикрепить наш элемент позже.

HTMLElement и теневой DOM

В файле index.js мы определим класс под названием «MyCircle», который расширит класс «HTMLElement», чтобы мы могли представить наш класс в дереве документа HTML.

В конструкторе мы должны создать наш Shadow DOM. Shadow DOM позволяет нам прикрепить к элементу скрытый отдельный DOM. Можем добавить стили, чтобы не вытекало наружу. Это означает, что у меня может быть два разных элемента с одним и тем же именем класса, однако они не будут влиять друг на друга, если стиль будет добавлен к тени. Это помогает нам избежать конфликтов между компонентами. {mode: ‘open’} указывает, что Shadow DOM доступен с помощью JS в нашем компоненте.

Мы добавим нашу функцию рендеринга для создания HTML-представления. С тенью мы можем добавить innerHTML и определить его, используя кавычки. InnerHTML может быть не лучшим решением здесь, но поскольку мы избегаем использования каких-либо библиотек, таких как Lit, innerHTML нас устраивает.

Обратные вызовы жизненного цикла

Теперь самое время упомянуть «обратные вызовы жизненного цикла» в веб-компонентах. В веб-компоненте HTMLElement существует четыре типа обратных вызовов жизненного цикла. Эти методы вызываются автоматически при изменении поведения пользовательского элемента. Определено четыре типа функций обратного вызова.

  1. connectedCallback: когда пользовательский элемент впервые прикрепляется к DOM документа, эта функция вызывается.
  2. attributeChangedCallback: позже мы увидим, как определить атрибуты для нашего пользовательского элемента. Этот метод запускается при обновлении значений атрибутов.
  3. adoptedCallback: вызывается, если настраиваемый элемент перемещается в другой документ.
  4. disconnectedCallback: вызывается, когда настраиваемый элемент удаляется или отключается от DOM документа.

Возвращаясь к нашему проекту, мы хотим включить connectCallback, потому что, когда наш пользовательский элемент подключен к документу, мы хотели бы отобразить его. Нам нужно добавить нашу функцию render() в connectCallback.

Определение пользовательского элемента как тега HTML

Нам нужно получить доступ к нашему пользовательскому элементу из html-файла. Как и в случае с «кнопкой», нам нужен способ прикрепить тег. customElements.define() — это функция для этого. Первым параметром будет тег, а вторым элементом будет наш класс пользовательского элемента, который мы визуализируем.

Я также добавил первоначальный стиль в файл innerHTML. Когда у нас будут атрибуты, мы будем изменять эти значения.

Теперь мы будем использовать тег my-circle в нашем index.html. Мы также добавим наш index.js в качестве скрипта для добавления пользовательского элемента.

Добавление дополнительных элементов к пользовательскому элементу

Теперь я сделаю два входа в свой пользовательский элемент, чтобы вызвать событие. Первый входной элемент будет принимать положительное число для передачи значения радиуса, а второй вход будет определять цвет моего круга. На данный момент мы не заботимся о стиле. Теперь наша функция рендеринга:

Установка атрибутов для тега HTML

HTML-элементы могут иметь атрибуты. Например, тег ‹input› имеет атрибут под названием «тип», поэтому, если мы присвоим ему значение «число», это не позволит нам ввести какой-либо текст в элемент ввода.

Для ‹my-circle› у нас будет два атрибута «радиус» и «цвет».

Чтобы сделать эти атрибуты действительными, нам нужно определить их как свойства в нашем классе MyCircle.

Во-первых, нам нужно добавить сообщить нашему классу, какие атрибуты может иметь этот тег. Это делается с помощью статических методов получения, называемых observedAttribute. После этого мы прикрепим крючок жизненного цикла attributeChangedCallback для вызова при изменении атрибутов (это будет сделано при изменении входных данных). Мы хотим, чтобы эти методы повторно отображали наше теневое представление HTML. Чтобы использовать этот хук, нам также нужно определить методы получения и установки для наших пользовательских атрибутов. Посмотрите, как я использовал эти свойства в стиле MyCircle.

Обработка событий

Теперь все, что мне нужно сделать, это соединить атрибуты цвета и радиуса с соответствующими входными значениями и прикрепить к ним пользовательское событие.

Во-первых, мне нужно передать начальные значения на входы. Затем я создам функции для прослушивания при изменении входных значений. Нам нужно добавить эти функции в connectedCallback для подключения при создании модели DOM и в attributeChangedCallback для повторного подключения прослушивателей событий при изменении атрибутов.

И это наш последний индекс. Методы «setAttribute» вызывают метод attributeChangedCallback, чтобы мы визуализировали компонент, чтобы увидеть результат. Смотрим конечный продукт:

Это оно!