Вопрос или проблема
Я создаю собственный обертку-компонент в Angular, чтобы расширить MatDivider
от Angular Material, но сталкиваюсь с проблемами, когда стили и свойства компонента из MatDivider
не применяются правильно. Цель состоит в том, чтобы абстрагировать MatDivider
, чтобы пользователи моей библиотеки не нуждались в прямом импорте Angular Material.
Вот моя текущая настройка:
Обертка-компонент (TypeScript):
import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';
import { MatDivider } from '@angular/material/divider';
/**
* `DividerComponent` является оберткой вокруг MatDivider от Angular Material.
* Он расширяет MatDivider и предназначен для предоставления той же функциональности
*
*/
@Component({
selector: 'aal-divider',
standalone: true,
template: '',
styleUrls: ['./divider.component.scss'],
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class DividerComponent extends MatDivider {}
SCSS (divider.component.scss):
@use '@angular/material' as mat;
@use '../../themes/theming' as *;
@include mat.divider-theme($aal--mat-light-theme);
Проблема
Когда я пытаюсь использовать DividerComponent
, предполагаемые стили и поведение из MatDivider
не кажутся примененными, даже несмотря на то, что я расширил класс. Я вижу класс mat-divider
в DOM, но он не отображается как ожидалось.
Вопрос
- Существует ли конкретное ограничение в Angular Material, которое препятствует расширению компонентов, таких как
MatDivider
? - Существуют ли другие подходы к обертке
MatDivider
эффективно, чтобы я мог управлять темой без необходимости пользователям напрямую импортировать Angular Material?
Любые рекомендации или предложения по обходным путям будут очень признательны!
Примечание: Главное, на что нужно обратить внимание в этом подходе, заключается в том, что существует дополнительный элемент, который оборачивает ваш материал-компонент, поэтому, если есть какой-либо CSS-селектор, такой как mat-list > mat-divider
, он не будет применяться из-за дополнительного вставленного HTML-элемента.
Вам нужно добавить MatListModule
в массив импортов, чтобы использовать директиву.
imports: [MatDividerModule],
Вам также нужно всегда включать mixins темы компонента
внутри обертки, я использовал :host
в качестве элемента-обертки.
@use '@angular/material' as mat;
@use '../styles' as *;
:host {
@include mat.divider-theme($theme);
}
Полный код:
TS:
import {
ChangeDetectionStrategy,
Component,
ViewEncapsulation,
} from '@angular/core';
import { MatDividerModule } from '@angular/material/divider';
import { MatListModule } from '@angular/material/list';
import { MatDivider } from '@angular/material/divider';
/**
* `DividerComponent` является оберткой вокруг MatDivider от Angular Material.
* Он расширяет MatDivider и предназначен для предоставления той же функциональности
*
*/
@Component({
selector: 'aal-divider',
standalone: true,
imports: [MatDividerModule],
template: '<mat-divider></mat-divider>',
styles: [
`
@use '@angular/material' as mat;
@use '../styles' as *;
:host {
@include mat.divider-theme($theme);
}
`,
],
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class DividerComponent extends MatDivider {}
/**
* @title Основной разделитель
*/
@Component({
selector: 'divider-overview-example',
templateUrl: 'divider-overview-example.html',
standalone: true,
imports: [MatListModule, DividerComponent, MatDividerModule],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class DividerOverviewExample {}
HTML:
<mat-list>
<mat-list-item>Элемент 1</mat-list-item>
<aal-divider></aal-divider>
<mat-list-item>Элемент 2</mat-list-item>
<aal-divider></aal-divider>
<mat-list-item>Элемент 3</mat-list-item>
</mat-list>
<hr />
<mat-list>
<mat-list-item>Элемент 1</mat-list-item>
<aal-divider></aal-divider>
<mat-list-item>Элемент 2</mat-list-item>
<aal-divider></aal-divider>
<mat-list-item>Элемент 3</mat-list-item>
</mat-list>
Демо Stackblitz
Ответ или решение
Проблема расширения Angular Material MatDivider в пользовательском компоненте
Создание пользовательского компонента, который оборачивает элементы Angular Material, в частности MatDivider
, может вызвать несколько сложностей из-за особенностей обработки стилей и структуры DOM. В этом ответе мы разберем возможные причины проблем с корректным наследованием стилей и поведением MatDivider
, а также предложим альтернативные подходы для решения данной ситуации.
Проектирование и текущая реализация
Для начала, рассмотрим вашу текущее определение компонента DividerComponent
, который вы создали для оборачивания MatDivider
:
import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';
import { MatDivider } from '@angular/material/divider';
@Component({
selector: 'aal-divider',
standalone: true,
template: '',
styleUrls: ['./divider.component.scss'],
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class DividerComponent extends MatDivider {}
В приведенном коде наблюдаются некоторые ключевые моменты:
- Неправильный шаблон: Ваша реализация включает пустой шаблон (
template: ''
), что не позволяетMatDivider
правильно отобразиться в DOM. - Структура стилей: В SCSS-стилях вы пытаетесь применить тему
divider-theme
, что нуждается в дополнительной обертке, такой как:host
.
Причины проблемы
-
Структура DOM: Когда вы наследуете от
MatDivider
, Angular Material добавляет своего рода обертку, что может вызвать проблемы с применением глобальных стилей, например, селекторов типаmat-list > mat-divider
, так как в результирующем HTML-дереве может быть лишний элемент. -
Отсутствие передачи контента: Поскольку шаблон пустой,
MatDivider
не получает контент для рендеринга. -
Импорт модулей: Вы не указали в
imports
необходимые модули, такие какMatDividerModule
, что может касаться всех директив, используемых в вашем компоненте.
Рекомендации по улучшению
Для исправления проблем с вашим пользовательским компонентом, вам следует:
- Обновить шаблон: Замените пустой шаблон на корректное использование
MatDivider
.
template: '<mat-divider></mat-divider>',
- Использование :host: Примените SCSS-миксины темы внутри селектора
:host
, чтобы гарантировать, что стили применяются корректно.
:host {
@include mat.divider-theme($theme);
}
- Импорт MatDividerModule: Не забудьте о включении модуля в массив
imports
.
imports: [MatDividerModule],
Полный обновленный код
Следует объединить все вышеперечисленные изменения в окончательном варианте вашего компонента:
import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';
import { MatDividerModule } from '@angular/material/divider';
import { MatDivider } from '@angular/material/divider';
@Component({
selector: 'aal-divider',
standalone: true,
imports: [MatDividerModule],
template: '<mat-divider></mat-divider>',
styles: [`
@use '@angular/material' as mat;
:host {
@include mat.divider-theme($theme);
}
`],
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class DividerComponent extends MatDivider {}
Заключение
Избегание проблем с переносом стилей и функциональности MatDivider
в пользовательский компонент подразумевает корректное использование Angular и пакета Material. Обязательно уделяйте внимание структуре HTML, применяемым стилям и необходимым импортам. Эти действия помогут вам создать более предсказуемый и управляемый интерфейс для пользователей вашего библиотеки, не требующих прямого импорта Angular Material.