Улучшение веб-компонента
На этой неделе мы рассмотрели, как создать первый веб-компонент и как добавить опции в веб-компонент.
Несколько разных подходов
Существует два подхода к прогрессивному улучшению веб-компонента (возможно, их больше, но я чаще всего использую именно эти два)…
- Если контент работает только с JavaScript, скройте его и показывайте только после создания экземпляра веб-компонента.
- Если контент работает без JavaScript, покажите HTML по умолчанию, а затем добавьте дополнительные интерактивные возможности на основе HTML и JavaScript после создания экземпляра веб-компонента.
Мы рассмотрим оба подхода, а также то, когда и почему стоит предпочесть один из них другому.
Подход 1. Скрыть контент
Для этого подхода давайте рассмотрим пример, используемый нами всю неделю, — компонент <wc-count>
, создающий кнопку-счётчик.
<wc-count>
<button>Clicked 0 Times</button>
</wc-count>
Кнопка абсолютно ничего не делает без JavaScript. Поэтому, вероятно, имеет смысл скрыть её, пока веб-компонент не будет готов.
Есть несколько способов сделать это…
Использование атрибута [hidden]
Один из способов сделать это — добавить к элементу атрибут [hidden]
.
<wc-count hidden>
<button>Clicked 0 Times</button>
</wc-count>
Затем в методе constructor()
при создании компонента можно удалить атрибут.
/**
* Конструктор класса
*/
constructor () {
// Всегда вызывайте super первым в конструкторе
super();
// ...
// Показываем элемент
this.removeAttribute('hidden');
}
Использование CSS
Псевдокласс :defined
предоставляет ещё один способ обнаружить, когда пользовательский элемент был определён с помощью только CSS, а не JavaScript.
Можно комбинировать его с псевдоклассом :not()
, чтобы скрыть элемент, пока он не будет определён.
/* Скроем элемент <wc-count> до тех пор, пока он не будет определён */
wc-count:not(:defined) {
display: none;
}
С резервным сообщением
Неплохо было бы загрузить резервное сообщение во время загрузки контента.
В этом примере обернём сообщение в элемент <wc-count-loading>
, и добавим атрибут [hidden]
к элементу <button>
.
<wc-count>
<button hidden>Clicked 0 Times</button>
<wc-count-loading>Loading...</wc-count-loading>
</wc-count>
Затем в методе constructor()
удалим атрибут [hidden]
из this.button
. Также используем метод Element.querySelector()
, чтобы получить элемент <wc-count-loading>
, и метод Element.remove()
, чтобы удалить его, когда контент будет готово.
/**
* Конструктор класса
*/
constructor () {
// Всегда вызывайте super первым в конструкторе
super();
// Свойства экземпляра
this.button = this.querySelector('button');
// ...
// Показываем элемент
this.button.removeAttribute('hidden');
this.querySelector('wc-count-loading')?.remove();
}
Подход 2. Слои в HTML и интерактивность
Этот подход отлично работает, когда есть контент, который хорош сам по себе, но ему не помешает дополнительная изюминка или интерактивность.
Например, представим, что вы создаёте группу аккордеонов с различными секциями раскрытия/свёртывания.
Можно начать с HTML, включающего заголовки и контент, например, так...
<accordion-group>
<h2>Why is Lil' Wayne hip-hop top 5 list?</h2>
<div>
<p>...</p>
</div>
<h2>How many spells could Merlin cast in a day?</h2>
<div>
<p>...</p>
</div>
</accordion-group>
Когда вы создаёте экземпляр веб-компонента в методе constructor()
, можно обновить пользовательский интерфейс, чтобы скрывать или показывать элементы по мере необходимости, вводить дополнительный HTML, добавлять необходимые атрибуты и так далее.
/**
* Создание экземпляра веб-компонента
*/
constructor () {
// Получаем все заголовки аккордеона
let headings = this.querySelectorAll('h2');
// Обновляем контент
for (let heading of headings) {
// Получаем совпадающий контент
let content = heading.nextElementSibling;
if (!content) continue;
// Создаём кнопку и копируем в неё содержимое заголовка
let btn = document.createElement('button');
btn.innerHTML = heading.innerHTML;
// Стираем содержимое заголовка и заменяем его кнопкой
heading.innerHTML = '';
heading.append(btn);
// Скрываем контент
content.setAttribute('hidden', '');
// Добавляем ARIA
btn.setAttribute('aria-expanded', false);
}
}
В итоге получаем HTML, выглядящий примерно так...
<accordion-group>
<h2><button>Why is Lil' Wayne hip-hop top 5 list?</button></h2>
<div hidden>
<p>...</p>
</div>
<h2><button>How many spells could Merlin cast in a day?</button></h2>
<div hidden>
<p>...</p>
</div>
</accordion-group>
Какой подход использовать
Я предпочитаю начинать с базового HTML и добавлять интерактивность, когда это возможно.
Если есть контент, который просто не работает с HTML, я постараюсь включить резервное сообщение, пока не загрузится веб-компонент, однако в противном случае скрою контент.
Все статьи серии о Веб-Компонентах/Web Component
- Ваш первый веб-компонент
- Добавление опций в веб-компонент
- Улучшение веб-компонента
- Различные способы инстанцирования веб-компонента
- Методы жизненного цикла веб-компонента
- Как обнаружить изменение атрибутов веб-компонента
- Как заставить веб-компоненты общаться (часть 1)
- Как заставить веб-компоненты общаться (часть 2)