Всем программерам привет! Тема сегодняшней рубрики - пользовательские элементы(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.
Всего доброго! Пока.