В COYO мы используем Angular Material в качестве технической основы для нашего пользовательского интерфейса. Библиотека предоставляет множество различных директив и компонентов, которые помогут вам реализовать надежный интерфейс на основе рекомендаций Material Design. Одним из основных компонентов библиотеки являются собственные <button> или <a> элементы, усиленные стилем Material Design и рябью чернил. К сожалению, у этих кнопок отсутствует состояние загрузки, указывающее на продолжающиеся асинхронные действия. Итак, давайте создадим нашу собственную директиву загрузки, чтобы добавить эту функциональность к кнопкам Angular Material.

Наша цель - добавить атрибут загрузки к элементу <button>, чтобы мы могли легко включать / выключать состояние загрузки. Во время загрузки кнопка должна отображать счетчик и не допускать никакого взаимодействия с пользователем. Размеры кнопки не должны изменяться при переключении состояния загрузки.

Шаг 1. Начиная с основы

Начнем с создания новой директивы MatButtonLoadingDirective. Поскольку мы хотим расширить существующий компонент кнопки Angular Material, мы используем тот же селектор, что и компонент. Вы можете найти селектор в исходном коде на GitHub. Мы просто копируем селектор и добавляем атрибут загрузки к каждому из них. Это гарантирует, что наша директива работает со всеми типами кнопок материалов и что мы можем просто установить атрибут loading для каждой из них.

Сама директива должна реализовывать ловушку OnChanges жизненного цикла Angular для выполнения действий при изменении атрибута загрузки. Когда loading активен, мы создаем новый счетчик внутри кнопки. Он снова удаляется, когда состояние loading снова меняется на false. Чтобы применить индивидуальный стиль, мы также добавляем к кнопке класс .mat-loading.

Шаг 2: реализация счетчика

Это сложная часть. Мы не хотим встраивать собственный счетчик в существующую кнопку. Намного больше мы хотим использовать уже существующий компонент MatProgressSpinner из библиотеки Angular. Мы будем использовать ComponentFactory для динамического создания нового экземпляра этого компонента и добавления его к существующей кнопке. Если вы хотите узнать больше о динамических компонентах, вы найдете руководство в документации Angular.

Прежде всего, мы меняем конструктор нашей директивы и внедряем все, что нам нужно. Мы также создаем новый экземпляр фабрики компонентов для MatProgressSpinner, чтобы мы могли легко создавать новые экземпляры в методе createSpinner.

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

Наконец, мы будем скрывать содержимое кнопки всякий раз, когда кнопка находится в состоянии загрузки. Сделаем это через visibility: hidden, чтобы размеры кнопки не менялись. Сам спиннер будет помещен в центр кнопки.

Шаг 3. Отключение кнопки

Это уже очень крутой результат. Теперь мы можем переключать состояние загрузки кнопки с помощью соответствующего атрибута. Он работает для каждой кнопки, которую предоставляет Angular Material. Однако кнопку можно нажать, если она находится в состоянии загрузки. Мы могли бы просто установить отключенное состояние прямо в нашем хуке жизненного цикла, но это привело бы к некорректному поведению. Мы бы переопределили отключенное состояние, которое может быть установлено на самой кнопке. Таким образом, мы используем еще один @Input, называемый disabled. Это будет тот же ввод, который сам компонент кнопки использует для определения своего отключенного состояния. Если кнопка загружается, мы отменяем отключенное состояние и устанавливаем для него значение true. В противном случае мы вернемся к отключенному состоянию на самой кнопке.

Шаг 4: Выбор правильной палитры темы

Одна незначительная деталь, которой все еще не хватает, - это правильный цвет прядильщика. Оба компонента - кнопка и счетчик - поддерживают использование цветовой палитры. Таким образом, мы можем легко согласовать цвет счетчика с цветом кнопки. Для этого мы добавляем в директиву еще один @Input и называем его color. Опять же, это тот же самый ввод, который кнопка будет использовать для определения своего цвета. Затем мы можем просто установить цвет на компоненте счетчика, который мы создаем в методе out createSpinner.

Окончательная реализация

Вот и все. Мы сделали! Мы создали удобное состояние загрузки для кнопок Angular Material. Есть несколько незначительных изменений, которые можно добавить в директиву (например, значение прогресса), но это выходит за рамки данной статьи. Вы можете найти окончательный результат в StackBlitz ниже. Повеселись!