Angular Mat Datepicker - 动态应用样式
Angular Mat Datepicker - Apply styles dynamically
我有一个包含 Material 日期选择器的日期选择器组件。该组件接收一个 datepickerConfig
对象,描述日期选择器的样式。例如,此对象描述要应用的阴影级别、焦点样式、悬停样式等。
我对 Material 样式还很陌生,所以我想知道如何在运行时动态应用这些样式?
例如,对于阴影,我在我的 SCSS 文件中声明了以下变量:
/* shadow */
$shadow-opacity: rgba(0, 0, 0, 0.3);
$dp-box-shadow-mobile: 0 30px 40px $shadow-opacity;
$dp-box-shadow-desktop-1: 0 3px 6px $shadow-opacity;
$dp-box-shadow-desktop-2: 0 6px 12px $shadow-opacity;
...
// more variables for the different styles
.mat-datepicker-content {
// dynamically apply variables to these styles
// e.g. if datepickerConfig.shadow.level === 2
// then $dp-box-shadow-desktop-2 should be applied
box-shadow: ...;
border: ...;
border-radius: ...;
...
}
在运行时,我需要检查 datepickerConfig
对象中的阴影级别,并动态地将正确的样式应用到元素。
我的日期选择器模板:
<mat-form-field appearance="fill">
<mat-label>Choose a date</mat-label>
<input matInput [matDatepicker]="picker">
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
<mat-datepicker #picker (opened)="opened()">
<mat-datepicker-actions>
<button mat-button matDatepickerCancel>CANCEL</button>
<button mat-raised-button matDatepickerApply>OK</button>
</mat-datepicker-actions>
</mat-datepicker>
</mat-form-field>
我怎样才能做到这一点,不仅是为了阴影,还有我必须动态设置的多种样式?我想知道使用 Angular 执行此操作的干净方法...或者这只能针对 class 使用 JS 来实现吗?
谢谢。
您可以使用 [ngStyle] directive——以这个例子为例,它根据条件动态设置宽度 属性。
<div [style.width.%]="condition ? 20 : 50" ...>
一旦您开始管理多个样式,使用 [ngStyle]
或上面的“更简洁”的替代语法可能会变得混乱,并且不能真正用于获取模板中不可用的投影内容。
我可能建议改用 class 方法(使用 [ngClass] attribute directive)并使用 SCSS 覆盖有条件地重置某些属性。
<mat-form-field class="datepicker"
[class.datepicker--modified]="condition">
...
// in the SCSS
.datepicker {
color: red;
&--modified {
color: blue;
}
}
您可以使用 CSS variables 实现您想要的。您不能使用 SCSS 变量,它们在 运行 时间对您不可用,因为它们在 SCSS 编译成 CSS.
时消失
Support for CSS variables 现在已经很不错了。虽然IE11没戏了
我在 stackblitz 中创建了一个示例,它使用 CSS 变量根据配置提供的值动态更改按钮阴影的样式:https://stackblitz.com/edit/angular-ivy-cuyhed?file=src/app/fancy-button.component.ts
全局样式包含 CSS 个变量的定义。
styles.css
:root {
/* shadow-opacity variables, that will be used based on the configuration */
--shadow-opacity-level-1: rgba(0, 0, 0, 1);
--shadow-opacity-level-2: rgba(0, 0, 0, 0.5);
/* default shadow opacity */
--shadow-opacity: var(--shadow-opacity-level-1);
}
/* global styles for a fancy-button, similar to your .mat-datepicker-content class */
.fancy-button {
border: 3px solid;
padding: 0.25em 0.5em;
/* here we use var(--shadow-opacity) to set default value, --shadow-opacity will be overridden later, based on the current configuration */
box-shadow: 5px 5px 0px 0px var(--shadow-opacity);
}
接下来我们需要一个按钮组件,它使用 .fancy-button
class,但也会根据当前配置值覆盖 --shadow-opacity
变量的值。
getButtonStyle()
方法检查 config.shadowLevel
值并将 --shadow-opacity
变量设置为适当的阴影级别。
花式-button.component.ts
@Component({
selector: 'fancy-button',
template: `
<button
class="fancy-button"
style="{{getButtonStyle()}}"
>
{{config.label}}
</button>
`,
styles: [``]
})
export class FancyButtonComponent {
@Input() config: FancyButtonConfig;
getButtonStyle(): string {
if (this.config.shadowLevel === 1) {
return '--shadow-opacity: var(--shadow-opacity-level-1)';
}
if (this.config.shadowLevel === 2) {
return '--shadow-opacity: var(--shadow-opacity-level-2)';
}
throw Error(`Unknown shadowLevel: ${this.config.shadowLevel}`);
}
}
总结
还可以选择使用自定义 classes 和覆盖,正如 Nathan 在他的 中所建议的那样。我认为 CSS 变量和 classes 覆盖是相当等价的方法,在这两者之间做出决定时,我会选择一种方法,该方法将产生更清晰、更易维护的代码。
资源
- Introduction to CSS Variables by Kevin Powell
- Overriding "parameter" of CSS class
使用 Angular Material 组件扩展的答案
问题是专门询问 Angular material 组件,但上面的回答描述了常规 HTML 按钮。
我已经使用包装 mat-raised-button
的 FancyButtonMatWrapperComponent
扩展了 stackblitz 演示,并根据提供的配置更改了它的 box-shadow
。
所有机制都按照上述常规 HTML 按钮的方式工作。主要区别在于,index.html 中的外部 div
具有 class material-overrides
,这有助于覆盖默认的 Angular Material 样式。
全局 styles.css
然后包含以下覆盖
.material-overrides .mat-raised-button {
border: 3px solid black;
padding: 0.25em 0.5em;
box-shadow: 5px 5px 0px 0px var(--shadow-opacity);
}
我有一个包含 Material 日期选择器的日期选择器组件。该组件接收一个 datepickerConfig
对象,描述日期选择器的样式。例如,此对象描述要应用的阴影级别、焦点样式、悬停样式等。
我对 Material 样式还很陌生,所以我想知道如何在运行时动态应用这些样式?
例如,对于阴影,我在我的 SCSS 文件中声明了以下变量:
/* shadow */
$shadow-opacity: rgba(0, 0, 0, 0.3);
$dp-box-shadow-mobile: 0 30px 40px $shadow-opacity;
$dp-box-shadow-desktop-1: 0 3px 6px $shadow-opacity;
$dp-box-shadow-desktop-2: 0 6px 12px $shadow-opacity;
...
// more variables for the different styles
.mat-datepicker-content {
// dynamically apply variables to these styles
// e.g. if datepickerConfig.shadow.level === 2
// then $dp-box-shadow-desktop-2 should be applied
box-shadow: ...;
border: ...;
border-radius: ...;
...
}
在运行时,我需要检查 datepickerConfig
对象中的阴影级别,并动态地将正确的样式应用到元素。
我的日期选择器模板:
<mat-form-field appearance="fill">
<mat-label>Choose a date</mat-label>
<input matInput [matDatepicker]="picker">
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
<mat-datepicker #picker (opened)="opened()">
<mat-datepicker-actions>
<button mat-button matDatepickerCancel>CANCEL</button>
<button mat-raised-button matDatepickerApply>OK</button>
</mat-datepicker-actions>
</mat-datepicker>
</mat-form-field>
我怎样才能做到这一点,不仅是为了阴影,还有我必须动态设置的多种样式?我想知道使用 Angular 执行此操作的干净方法...或者这只能针对 class 使用 JS 来实现吗?
谢谢。
您可以使用 [ngStyle] directive——以这个例子为例,它根据条件动态设置宽度 属性。
<div [style.width.%]="condition ? 20 : 50" ...>
一旦您开始管理多个样式,使用 [ngStyle]
或上面的“更简洁”的替代语法可能会变得混乱,并且不能真正用于获取模板中不可用的投影内容。
我可能建议改用 class 方法(使用 [ngClass] attribute directive)并使用 SCSS 覆盖有条件地重置某些属性。
<mat-form-field class="datepicker"
[class.datepicker--modified]="condition">
...
// in the SCSS
.datepicker {
color: red;
&--modified {
color: blue;
}
}
您可以使用 CSS variables 实现您想要的。您不能使用 SCSS 变量,它们在 运行 时间对您不可用,因为它们在 SCSS 编译成 CSS.
时消失Support for CSS variables 现在已经很不错了。虽然IE11没戏了
我在 stackblitz 中创建了一个示例,它使用 CSS 变量根据配置提供的值动态更改按钮阴影的样式:https://stackblitz.com/edit/angular-ivy-cuyhed?file=src/app/fancy-button.component.ts
全局样式包含 CSS 个变量的定义。
styles.css
:root {
/* shadow-opacity variables, that will be used based on the configuration */
--shadow-opacity-level-1: rgba(0, 0, 0, 1);
--shadow-opacity-level-2: rgba(0, 0, 0, 0.5);
/* default shadow opacity */
--shadow-opacity: var(--shadow-opacity-level-1);
}
/* global styles for a fancy-button, similar to your .mat-datepicker-content class */
.fancy-button {
border: 3px solid;
padding: 0.25em 0.5em;
/* here we use var(--shadow-opacity) to set default value, --shadow-opacity will be overridden later, based on the current configuration */
box-shadow: 5px 5px 0px 0px var(--shadow-opacity);
}
接下来我们需要一个按钮组件,它使用 .fancy-button
class,但也会根据当前配置值覆盖 --shadow-opacity
变量的值。
getButtonStyle()
方法检查 config.shadowLevel
值并将 --shadow-opacity
变量设置为适当的阴影级别。
花式-button.component.ts
@Component({
selector: 'fancy-button',
template: `
<button
class="fancy-button"
style="{{getButtonStyle()}}"
>
{{config.label}}
</button>
`,
styles: [``]
})
export class FancyButtonComponent {
@Input() config: FancyButtonConfig;
getButtonStyle(): string {
if (this.config.shadowLevel === 1) {
return '--shadow-opacity: var(--shadow-opacity-level-1)';
}
if (this.config.shadowLevel === 2) {
return '--shadow-opacity: var(--shadow-opacity-level-2)';
}
throw Error(`Unknown shadowLevel: ${this.config.shadowLevel}`);
}
}
总结
还可以选择使用自定义 classes 和覆盖,正如 Nathan 在他的
资源
- Introduction to CSS Variables by Kevin Powell
- Overriding "parameter" of CSS class
使用 Angular Material 组件扩展的答案
问题是专门询问 Angular material 组件,但上面的回答描述了常规 HTML 按钮。
我已经使用包装 mat-raised-button
的 FancyButtonMatWrapperComponent
扩展了 stackblitz 演示,并根据提供的配置更改了它的 box-shadow
。
所有机制都按照上述常规 HTML 按钮的方式工作。主要区别在于,index.html 中的外部 div
具有 class material-overrides
,这有助于覆盖默认的 Angular Material 样式。
全局 styles.css
然后包含以下覆盖
.material-overrides .mat-raised-button {
border: 3px solid black;
padding: 0.25em 0.5em;
box-shadow: 5px 5px 0px 0px var(--shadow-opacity);
}