Как обнаружить изменение атрибутов веб-компонента
Ранее мы рассмотрели жизненный цикл веб-компонента. Хотя веб-компоненты не обладают реактивностью данных, один из методов жизненного цикла, встроенный в API веб-компонента, может использоваться для обнаружения изменения атрибута вашего элемента.
Метод attributeChangedCallback()
Метод attributeChangedCallback()
является частью жизненного цикла веб-компонента и запускается каждый раз, когда атрибут веб-компонента добавляется, удаляется или изменяется его значение.
Он принимает три аргумента: name
(имя) изменяемого атрибута, его oldValue
(старое значение) и newValue
(новое значение).
/**
* Выполняется при изменении значения атрибута компонента
* @param {String} name Имя атрибута
* @param {String} oldValue Старое значение атрибута
* @param {String} newValue Новое значение атрибута
*/
attributeChangedCallback (name, oldValue, newValue) {
console.log('attribute changed', name, oldValue, newValue, this);
}
По соображениям производительности метод attributeChangedCallback()
следит и реагирует только на те атрибуты, которые были указаны.
Для этого создаётся статическое свойство observedAttributes
, значением которого является массив атрибутов для наблюдения.
Можно использовать любые атрибуты, включая нестандартные. В этом примере укажем веб-компоненту следить за изменениями атрибутов [text]
и [pause]
.
// Определяем атрибуты для наблюдения
static observedAttributes = ['text', 'pause'];
/**
* Выполняется при изменении значения атрибута компонента
* @param {String} name Имя атрибута
* @param {String} oldValue Старое значение атрибута
* @param {String} newValue Новое значение атрибута
*/
attributeChangedCallback (name, oldValue, newValue) {
console.log('attribute changed', name, oldValue, newValue, this);
}
Теперь можно сделать что-то вроде этого…
let count = document.querySelector('wc-count');
// logs "attribute changed" "text" null "You clicked it: {{count}}"
count.setAttribute('text', 'You clicked it: {{count}}');
Но если изменить атрибут, которого нет в списке observedAttributes
, ничего не произойдёт.
// Ничего не происходит
count.setAttribute('id', 'count-1234');
В этом примере данные выводятся в консоль. Можно включить панель Инспектор и перейти во вкладку консоль и увидеть результат выполнения скрипта там. Или перейти на сайт CodePen с этим примером.
Реагирование на изменение атрибутов веб-компонента
Теперь, когда мы обнаруживаем изменения атрибутов, можем реагировать на них.
Например, когда атрибут [text]
добавляется или изменяется в элементе <wc-count>
, можно обновить свойство this.text
и перерисовать текст в this.button
с обновлённым текстом.
/**
* Выполняется при изменении значения атрибута компонента
* @param {String} name Имя атрибута
* @param {String} oldValue Старое значение атрибута
* @param {String} newValue Новое значение атрибута
*/
attributeChangedCallback (name, oldValue, newValue) {
// Если атрибут [text], обновляем this.text и отображаем текст кнопки
if (name === 'text') {
this.text = newValue;
this.button.textContent = this.text.replace('{{count}}', this.count);
}
}
И, возможно, при добавлении атрибута [pause]
мы перестанем считать клики и [disable]
кнопку.
/**
* Выполняется при изменении значения атрибута компонента
* @param {String} name Имя атрибута
* @param {String} oldValue Старое значение атрибута
* @param {String} newValue Новое значение атрибута
*/
attributeChangedCallback (name, oldValue, newValue) {
// Если атрибут [text], обновляем this.text и отображаем текст кнопки
if (name === 'text') {
this.text = newValue;
this.button.textContent = this.text.replace('{{count}}', this.count);
}
// Если атрибут [pause] останавливаем отсчёт.
if (name === 'pause') {
this.button.removeEventListener('click', this);
this.button.setAttribute('disabled', '');
}
}
Когда атрибут [pause]
будет удалён, возможно, нам захочется начать подсчёт заново.
Для этого проверяем значение параметра newValue
. Если оно равно null
, то атрибут был удалён. В противном случае он был добавлен.
/**
* Выполняется при изменении значения атрибута компонента
* @param {String} name Имя атрибута
* @param {String} oldValue Старое значение атрибута
* @param {String} newValue Новое значение атрибута
*/
attributeChangedCallback (name, oldValue, newValue) {
// Если атрибут [text], обновляем this.text и отображаем текст кнопки
if (name === 'text') {
this.text = newValue;
this.button.textContent = this.text.replace('{{count}}', this.count);
}
// Если атрибут [pause] останавливаем отсчёт.
if (name === 'pause') {
if (newValue === null) {
this.button.addEventListener('click', this);
this.button.removeAttribute('disabled');
} else {
this.button.removeEventListener('click', this);
this.button.setAttribute('disabled', '');
}
}
}
Организация кода
Если вы отслеживаете несколько атрибутов, функция attributeChangedCallback()
может стать довольно громоздкой.
Чтобы было проще работать, я стараюсь абстрагировать код для обработки этих изменений в методах-обработчиках. Я добавляю к ним префикс handlechange*
, где *
— имя атрибута.
/**
* Обработка изменений атрибута [text]
* @param {String} oldValue Старое значение атрибута
* @param {String} newValue Новое значение атрибута
*/
handlechangetext (oldValue, newValue) {
this.text = newValue;
this.button.textContent = this.text.replace('{{count}}', this.count);
}
/**
* Обработка изменений атрибута [pause]
* @param {String} oldValue Старое значение атрибута
* @param {String} newValue Новое значение атрибута
*/
handlechangepause (oldValue, newValue) {
if (newValue === null) {
this.button.addEventListener('click', this);
this.button.removeAttribute('disabled');
} else {
this.button.removeEventListener('click', this);
this.button.setAttribute('disabled', '');
}
}
Затем, в методе attributeChangedCallback()
, можно автоматически запустить нужный метод с помощью скобочной нотации и шаблонного литерала. Передав в него oldValue
и newValue
.
/**
* Выполняется при изменении значения атрибута компонента
* @param {String} name Имя атрибута
* @param {String} oldValue Старое значение атрибута
* @param {String} newValue Новое значение атрибута
*/
attributeChangedCallback (name, oldValue, newValue) {
this[`handlechange${name}`](oldValue, newValue);
}
Все статьи серии о Веб-Компонентах/Web Component
- Ваш первый веб-компонент
- Добавление опций в веб-компонент
- Улучшение веб-компонента
- Различные способы инстанцирования веб-компонента
- Методы жизненного цикла веб-компонента
- Как обнаружить изменение атрибутов веб-компонента
- Как заставить веб-компоненты общаться (часть 1)
- Как заставить веб-компоненты общаться (часть 2)