Блог веб разработки статьи | видеообзоры | исходный код

Блог веб разработки статьи | видеообзоры | исходный код

webfanat вконтакте webfanat youtube

Пользовательские элементы в javascript

Пользовательские элементы в javascript

Всем программерам привет! Тема сегодняшней рубрики - пользовательские элементы(Custom Elements). Поехали!

Стандартизация html предоставляет нам множество различных элементов (p, h1, video, iframe ...) каждый из которых имеет свои стили и выполняет определенный функционал. Если стандартных элементов(тегов) для выполнения задачи недостаточно то мы может с помощью javascript создать и зарегистрировать свои собственные.

Пример:

<date-tag></date-tag>
<script>
  customElements.define('date-tag',
      class extends HTMLElement {
        constructor() {
          super();
          this.innerText = new Date().toLocaleDateString();
        }
      }
    );
</script>

Здесь мы создали тег 'date-tag' который выводит текущую дату. Для регистрации тега и написании его функционала мы обратились к глобальному объекту customElements и вызвали его метод define(). Данный метод принимает два обязательных аргумента: название тега(важно чтобы в названии присутствовал дефис) и класс(конструктор) который будет отвечать за операции на тегом(создание, изменение, удаление, отображение и т п). Обратите внимание что класс анонимный(не имеет названия) так как мы его писали прямо в качестве параметра метода define(). При необходимости мы можем просто вынести класс отдельно.

class MyTagDate  extends HTMLElement{
  constructor() {
    super();
    this.innerText = new Date().toLocaleDateString();
  }
}
customElements.define('date-tag', MyTagDate);

Аналогичная запись предыдущей, только здесь мы вынесли класс отдельно от метода define() и дали ему название 'MyTagDate'. В качестве родителя класса мы указываем 'HTMLElement'. HTMLElement представляет собой абстрактный класс отвечающий за регистрацию и управление новыми элементами, его нужно указывать обязательно. В конструкторе класса мы описали простую логику - вывод текущей даты. Как вы заметили обращение к самому элементу внутри класса идет через ключевое слово this, то есть при создании нового тега 'date-tag' создается новый объект нашего класса.

Теперь попробуем немного расширить функционал нашего элемента.

<date-tag></date-tag>
<script>
customElements.define('date-tag',
    class extends HTMLElement {
      constructor() {
        super();
          if(this.hasAttribute('time')){
           if(!this.hasAttribute('date')){
             this.times('toLocaleTimeString');
           }else{
             this.times('toLocaleString');
           }
         }
        else{
            this.innerText = new Date().toLocaleDateString();
        }
      }
      
    times(method){
        this.innerText = new Date()[method]();
        var el = this;
        setInterval(function(){
          el.innerText = new Date()[method]();
        }, 1000);
      }

    }
  );
</script>

Здесь мы добавили проверку на наличие у элемента атрибутов date и time. Метод times() служит для обновления времени(хода секунд).

<date-tag ></date-tag>
<date-tag  time></date-tag>
<date-tag  time date></date-tag>

Если нет атрибутов, то выводим только дату, если есть атрибут time выводим только время, а если есть (time, date) выводится дата и время. Вот такой механизм управления тегом date-tag мы создали!

Далее рассмотрим методы по отслеживанию изменений состояния элемента.

<date-tag ></date-tag>
<date-tag ></date-tag>
<script>
  customElements.define('date-tag',
    class extends HTMLElement {
      constructor() {
        super();
          if(this.hasAttribute('time')){
           if(!this.hasAttribute('date')){
             this.times('toLocaleTimeString');
           }else{
             this.times('toLocaleString');
           }
         }
        else{
            this.innerText = new Date().toLocaleDateString();
        }
      }

      times(method){
        this.innerText = new Date()[method]();
        var el = this;
        setInterval(function(){
          el.innerText = new Date()[method]();
        }, 1000);
      }

      connectedCallback() {
        console.log('Добавлен новый date-tag в document');
      }

      disconnectedCallback(){
           console.log('Удален date-tag');
      }

      static get observedAttributes() {
        return ['time', 'date'];
      }

      attributeChangedCallback(name, oldValue, newValue) {
        console.log('Изменен атрибут ' + name);
        if(oldValue !== null){
            console.log('Старое значение ' + oldValue);
        }
        console.log('Новое значение ' + newValue);
      }
    }
  );
</script>

В данном примере нас интересуют четыре наследуемых метода - connectedCallback(), disconnectedCallback(), observedAttributes(), attributeChangedCallback().

connectedCallback() - метод вызывается при добавлении(регистрации) элемента в document(DOM) страницы.

disconnectedCallback() - метод вызывается при удалении элемента.

observedAttributes() - статический метод который возвращает массив с названиями атрибутов изменение которых будет отслеживаться.

attributeChangedCallback() - метод который выводит данные о изменении атрибута(название, старое значение, новое значение).

С этим я думаю все понятно. Идем дальше!

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

Делается это так.

<button is="my-button" >Кнопка</button>
<script>
  customElements.define('my-button',
    class extends HTMLButtonElement {
      constructor() {
        super();
        this.style = `font-style:italic;`;
        if(this.hasAttribute('redirect')){
          this.addEventListener('click', function(){
            window.location = this.getAttribute('redirect');
          });
        }

      }
    },
    {extends: 'button'}
  );
</script>

Рассмотрим подробнее! Дана кнопка (button), мы регистрируем пользовательский элемент с названием 'my-button' и через специальный атрибут is присваиваем это название кнопке. Обратите внимание что класс наследуется от интерфейса HTMLButtonElement(элемент кнопки), также в методе define() указан дополнительный параметр в виде объекта {extends: 'button'} который явно указывает что мы работает с тегом button. Важно чтобы все это было соблюдено, иначе работать не будет!

В конструкторе описана логика которая будет расширять функционал кнопки. Текст кнопки становится курсивным.

<button is="my-button" redirect="https://webfanat.com">Кнопка</button>

При наличии атрибута redirect будет производится перенаправление на указанный адрес. Вот так это в принципе работает.

Для расширения прочих элементов (p, a, input и т п) вам понадобится обращаться к другим интерфейсам. Все доступные интерфейсы HTMLElement вы можете посмотреть на этом ресурсе.

А на этом у меня все. Надеюсь данная статья расширит ваш кругозор и вы обязательно найдете применение данной информации.

Не забывайте подписываться в группу Вконтакте и переходите на канал Youtube.

Всего доброго! Пока.

Оцените статью:

Статьи

Комментарии

Внимание!!! Все комментарии проходят модерацию перед публикацией!

В данном разделе пока нет комментариев!

Реклама

Запись экрана

Данное расширение позволяет записывать экран и выводит видео в формате webm