Создание лейаутов и сеток с помощью Angular CDK и Angular Material
В данной статье приведу пример решения с использованием размеров и устройств, которые предлагает Angular CDK.
В результате получим следующее:
Одним из минусов документации по Angular Material является отсутствие примеров работы с Angular CDK. В результате чего, некоторые разработчики начинают изобретать собственные решения для создания сеток и лейаутов, хотя все это можно реализовать средствами Angular CDK.
Ранее я уже писал о реализации колонок как в Bootstrap — Banx. Создание базового лейаута в Angular, а также использовал данное решение в цикле статей про тестовое задание — Тестовое задание на Angular. Создание UI kit для приложения.
Однако требования к приложениям меняются, как и меняются подходы к разработке. Сейчас я не вижу смысла в создании десятков вариантов сеток, которые почти не используются в приложении. Трех вариантов устройств достаточно, для реализации удобных пользовательских интерфейсов.
Установка
Для работы ниже описанных методов необходим Angular приложение с добавленным пакетом Angular Material.
Для создания проекта можно использовать следующую команду:
ng new my project
Для добавления material нужно выполнить команду:
ng add @angular/material
Отмечу, что пакеты нужно добавлять именно с помощью angular-cli
или nx
, так после установки пакета необходимо сконфигурировать тему. Все это зашито в скриптах, которые выполнятся сами, если добавлять пакет через angular-cli, а не с помощью yarn
или npm
.
Обзор Layouts
В документации по CDK есть отличный раздел, в котором приведены примеры обработки media
запросов CSS — Layouts.
В данном случае имеется следующая таблица:
CDK представляет следующий объект:
Это позволяет реализовывать макеты для 3 платформ, с двумя состояниями (portrait
, lanscape
):
- Мобильные устройства —
Handset
- Планшеты —
Tablet
- ПК —
Web
Для современной веб-разработки это более чем достаточно, но нет никаких проблем добавить еще несколько платформ и состояний.
Также вместе с Breakpoints
, CDK предоставляет сервис для отслеживания изменений размера экрана, для определения текущего размера — BreakpointObserver
.
Пример использования сервиса из документации:
В данном случае, перечисляются необходимые размеры для отслеживания, и когда размер меняется, то срабатывает подписка.
Создание макета с отслеживанием изменения платформы
Для создания макета с изменением платформы создадим новый модуль и компонент:
ng g m layout
ng g c layout
Если использовать Nx, тогда можно все это вынести в отдельную либу и команды будут следующими:
nx g lib ui/layout
nx g c layout --project=ui-layout
Так как тип платформы может понадобиться не только в компоненте layout’а, создадим сервис LayoutService
:
Как видно из реализации, идет подписка на все виды платформ, а затем все состояния объединяются и возвращается базовая платформа с помощью соответствия типу:
export const LAYOUT_SHORT_TYPES_MAP = {
[Breakpoints.Handset]: Breakpoints.Handset,
[Breakpoints.HandsetPortrait]: Breakpoints.Handset,
[Breakpoints.HandsetLandscape]: Breakpoints.Handset,
[Breakpoints.Tablet]: Breakpoints.Tablet,
[Breakpoints.TabletPortrait]: Breakpoints.Tablet,
[Breakpoints.TabletLandscape]: Breakpoints.Tablet,
[Breakpoints.Web]: Breakpoints.Web,
[Breakpoints.WebPortrait]: Breakpoints.Web,
[Breakpoints.WebLandscape]: Breakpoints.Web,
};
Где в подписке идет сопоставление типу:
type = LAYOUT_SHORT_TYPES_MAP[query];
Если нужно различать состояния, то нужно просто приравнивать найденный тип:
type = query;
Это необходимо только в том случае, если ваш UI должен реагировать на поворот устройства, изменяясь с альбомной на книжную ориентацию.
Создадим макет с 3 вариантами отображения:
Добавим соответствующую логику в LayoutComponent:
В самом компоненте добавим ранее созданный сервис и подпишемся на изменения размера экрана:
export class LayoutComponent implements OnInit {
readonly breakpoints = Breakpoints;
layoutType$!: Observable<string>;
constructor(private readonly layoutService: LayoutService) {}
ngOnInit(): void {
this.layoutType$ = this.layoutService.layoutType$;
}
}
В html добавим отображение компонентов для соответствующего типа экрана:
<ng-container [ngSwitch]="layoutType$ | async">
<ng-container *ngSwitchCase="breakpoints.Web">
<banshop-header></banshop-header>
<main class="web" automation-id="web">
<banshop-container>
<router-outlet></router-outlet>
</banshop-container>
</main>
<banshop-footer></banshop-footer>
</ng-container>
<ng-container *ngSwitchCase="breakpoints.Tablet">
<banshop-sidebar></banshop-sidebar>
<main class="tablet" automation-id="tablet">
<banshop-container mode="fluid">
<router-outlet></router-outlet>
</banshop-container>
</main>
</ng-container>
<ng-container *ngSwitchDefault>
<div>
<banshop-header></banshop-header>
<main class="handset" automation-id="handset">
<banshop-container mode="fluid">
<router-outlet></router-outlet>
</banshop-container>
</main>
</div>
<banshop-menu></banshop-menu>
</ng-container>
</ng-container>
Из примера видно, что в макете реализованы три варианта.
Примеры всех используемых компонентов я приводить не буду. Компоненты можно посмотреть в репозитории banshop.
Последним важным нюансом является реакция на смену экрана. И если с точки зрения JS есть подписка, то для того чтобы CSS знал о используемых размерах, можно создать несколько mixin’ов для упрощения верстки:
Если посмотреть миксины, то там просто обертка над таблицей размеров в Angular CDK.
Пример использования миксинов есть в layout.component.scss
:
@use 'libs/ui/stylesheets/mixins' as store-mixins;
:host {
display: flex;
min-height: 100%;
flex-direction: column;
width: 100%;
@include store-mixins.media-tablet() {
flex-direction: row;
}
@include store-mixins.media-web() {
flex-direction: column;
}
}
В данном случае, при изменении расширения будут применяться стили либо для handset
, либо для tablet
или web
.
Так как используется принцип mobile first, стили размещены от меньшего расширения к большему.
Если запустить проект, то получим следующее:
Резюме
В данной статье рассмотрели представленные варианты размеров из Angular CDK:
- handset — мобильное устройство
- tablet — планшет
- web — пк
Для определения типа устройства, добавили глобальный сервис LayoutService
, который с помощью BreakpointObserver
наблюдает за сменой экрана.
При изменении экрана в html
макете реализовали смену отображения компонентов в зависимости от текущего устройства.
Ссылки
Все исходники находятся на github, в репозитории:
Для того, чтобы посмотреть состояние проекта на момент написания статьи, нужно выбрать соответствующий тег — layouts.
Подписывайтесь на блог, чтобы не пропустить новые статьи про Angular, и веб-разработку. Medium | Telegram| VK | FB | Tw | Inst | Ln