От автора: цель статьи: изучить один из способов динамического изменения свойств CSS Grid с помощью Angular @HostBindingDecorator.
Исходный код / демо-версия: StackBlitz
Наше приложение
CSS Grid (контейнер и элементы)
Наша CSS Grid будет состоять из двух компонентов Angular. Родитель / контейнер и дочерний элемент. CSS Grid — это относительно новое соглашение для написания CSS, которое позволяет создавать реактивные сетки для размещения и выравнивания элементов.
<app-container> <app-item id="Hello"></app-item> <app-item [id]="2"></app-item> <app-item [id]="3"></app-item> <app-item [id]="4"></app-item> <app-item [id]="5"></app-item> ... </app-container>
С помощью селектора :host, компоненты Angular могут сами выполнять выбор. Мы можем использовать эту концепцию для обработки компонентов, таких как grid-контейнер или grid-элементы, и избегать использования оболочки div.
:host { /* CSS-Grid Properties */ display: grid; gap: 10px; grid-template-rows: repeat(3, 1fr); grid-auto-flow: column; height: 250px; }
display: grid: определяет элемент как grid-контейнер
grid-template-rows: определяет максимальное количество строк и размер строки
grid-auto-flow: column: указывает сетке создать новый столбец (вместо новой строки), когда ему не хватает места по вертикали.
gap: определяет зазор между каждым элементом.
В нашем примере каждая строка будет занимать 1 часть пространства. Поскольку в нашем случае мы указали 3 строки repeat(3, 1fr), каждая строка будет занимать 1/3 высоты элемента div. Столбцы будут занимать место в зависимости от размера контекста.
Советы по CSS Grid
Хотите центрировать что-то в грид-элементах? Сделайте сами элементы сетки контейнерами сетки и используйте justify-items и align-items.
.grid-item-class-name { display: grid; justify-items: center; align-items: center; }
Привязка хоста
Теперь, когда у нас есть базовое понимание таблицы, мы можем получить доступ к свойствам CSS в Angular Component Class.
import { Component, HostBinding} from '@angular/core'; export class ContainerComponent { /* These are the values we will allow the user to modify */ gapInPx = 10; rowsInFr = 3; /* These will give us access to our styles inside our class */ @HostBinding('style.gap') gap; @HostBinding('style.grid-template-rows') rows; }
Привязка хоста позволяет нам получать доступ и применять стили и классы CSS к компоненту. Мне нравится думать об этом, как об обновлении свойств селектора :host с помощью TypeScript.
export class ContainerComponent { // ... we will invoke this in a subscription later if (val) this.gapInPx += 5; // Increment was clicked else if (this.gapInPx > 0) this.gapInPx -= 5; // Decrement was clicked this.gap = `${this.gapInPx}px`; // Update gap with Template String // ... val will be our input from the subscription }
Обновление переменной HostBinding изменит значение свойства CSS для компонента. Мы можем подключить это к событию, чтобы дать возможность пользователю обновлять сетку.
Советы по Angular
Мы также можем добавлять и удалять классы, используя @HostBinding:
export class MyComponent { @HostBinding('class.is-valid') get validValue() { return this.value.valid; } }
Обработка событий
Теперь, когда Angular и CSS Grid объединены с помощью HostBinding. Мы предоставим пользователю возможность (с ограничением) обновлять grid-template-columns и gap.
Использование Angular Directive — это простой способ, позволяющий родственным компонентам связываться друг с другом. При нажатии кнопки мы отправим событие в контейнер для обновления привязки хоста.
import { DomSanitizer } from '@angular/platform-browser'; export class ContainerComponent { // ... constructor(private connector: ConnectorDirective, private sanitizer: DomSanitizer) {} ngOnInit() { // Subscribe to gap updates this.connector.updatedGap.subscribe(val => { if (val) this.gapInPx += 5; else if (this.gapInPx > 0) this.gapInPx -= 5; this.gap = `${this.gapInPx}px`; }); // Subscribe to row updates this.connector.updateRows.subscribe(val => { if (val) this.rowsInFr += 1; else if (this.rowsInFr > 1) this.rowsInFr -= 1; this.rows = this.sanitizer.bypassSecurityTrustStyle(`repeat(${this.rowsInFr}, 1fr)`); }); } }
Приведенный выше код выполняет следующее:
Подписывается на обновления зазора, изменяя зазор на 5px, что увеличивает или уменьшает зазор между элементами сетки
Подписывается на обновления рядов, изменяя первый параметр repeat() на 1, что увеличивает или уменьшает количество рядов в сетке.
Проверяет зазоры и ряды, чтобы убедиться, что мы не опустились ниже предела 1 для рядов или 0 для зазора.
Использует DOM Sanitizer, чтобы дать нам возможность передавать стиль как String.
Исходный код для кнопок и директивы вы можете найти на StackBlitz; они просты. Всю тяжелую работу выполняет контейнер.
Советы по Angular
Если родитель содержит директиву, все дочерние элементы родителя могут внедрить этот экземпляр директивы в свой класс Typescript.
<!-- HTML --> <app-container appConnector> <app-item id="Hello"></app-item> <app-item id="2"></app-item> <app-item id="3"></app-item> </app-container>/* TypeScript */ export class ItemComponent { constructor(public appConnector: ConnectorDirective) { this.appConnector.eventEmitter.subscribe(...) } }
Очистка DOM
Существует множество статей и ресурсов, посвященных изучению Angular’s DOM Sanitizer.
Без использования bypassSecurityTrustStyle
Вот вкратце мое мнение. Если мы фиксируем, где пользователь может отправлять входные данные и какие входные данные пользователь может отправлять, это можно считать «безопасным» для обхода Angular DOM Sanitizer.
import { DomSanitizer } from '@angular/platform-browser'; export class ContainerComponent { constructor(private sanitizer: DomSanitizer) {} this.rows = this.sanitizer .bypassSecurityTrustStyle(`repeat(${this.rowsInFr}, 1fr)`); }
Мы разрешаем пользователю обновить первый параметр в функции CSS repeat(). Мы ограничиваем ввод пользователя нажатием кнопки; мы контролируем значение, которое генерирует клик.
Заключение
Селектор Angular :host позволяет нам работать с такими компонентами, как css-grid или css-grid-items
Angular @HostBindingDecorator позволяет получать доступ и обновлять классы и стили CSS
Angular защищает потенциально опасные обновления DOM. Мы должны подумать о том, где и что мы разрешаем пользователям обновлять, минуя этот функционал.
Спасибо за чтение!
Автор: Erxk Verduin
Источник: https://itnext.io
Редакция: Команда webformyself.