如何让 Angular 组件动画跟随 CSS 类的变化,而不是静态样式?

Posted

技术标签:

【中文标题】如何让 Angular 组件动画跟随 CSS 类的变化,而不是静态样式?【英文标题】:How can I make Angular component animations follow CSS class changes, rather than static styles? 【发布时间】:2021-10-05 10:35:50 【问题描述】:

我创建了一个块光标日期/时间输入字段,它使用 Angular 状态和动画来指示正在进行的状态(如被禁用)或动画过渡状态(如输入无效击键时的红色闪烁)。这些输入字段可以在这里看到:https://skyviewcafe.com/

export const BACKGROUND_ANIMATIONS = trigger('displayState', [
  state('error',     style( backgroundColor: getBackgroundColor(ERROR_BACKGROUND, '#F67') )),
  state('normal',    style( backgroundColor: getBackgroundColor(NORMAL_BACKGROUND, 'white') )),
  state('confirm',   style( backgroundColor: getBackgroundColor(CONFIRM_BACKGROUND, '#6C6') )),
  state('warning',   style( backgroundColor: getBackgroundColor(WARNING_BACKGROUND, '#FC6') )),
  state('view-only', style( backgroundColor: getBackgroundColor(VIEW_ONLY_BACKGROUND, 'black') )),
  state('disabled',  style( backgroundColor: getBackgroundColor(DISABLED_BACKGROUND, '#CCC') )),
  state('dark-error',     style( backgroundColor: getBackgroundColor(ERROR_BACKGROUND, '#C36', true) )),
  state('dark-normal',    style( backgroundColor: getBackgroundColor(NORMAL_BACKGROUND, '#333', true) )),
  state('dark-confirm',   style( backgroundColor: getBackgroundColor(CONFIRM_BACKGROUND, '#292', true) )),
  state('dark-warning',   style( backgroundColor: getBackgroundColor(WARNING_BACKGROUND, '#B80', true) )),
  state('dark-view-only', style( backgroundColor: getBackgroundColor(VIEW_ONLY_BACKGROUND, '#0A0', true) )),
  state('dark-disabled',  style( backgroundColor: getBackgroundColor(DISABLED_BACKGROUND, '#444', true) )),
  transition('normal => error',   animate(FLASH_DURATION)),
  transition('error => normal',   animate(FLASH_DURATION)),
  transition('normal => confirm', animate(FLASH_DURATION)),
  transition('confirm => normal', animate(FLASH_DURATION)),
  transition('warning => error',  animate(FLASH_DURATION)),
  transition('error => warning',  animate(FLASH_DURATION)),
  transition('dark-normal => dark-error',   animate(FLASH_DURATION)),
  transition('dark-error => dark-normal',   animate(FLASH_DURATION)),
  transition('dark-normal => dark-confirm', animate(FLASH_DURATION)),
  transition('dark-confirm => dark-normal', animate(FLASH_DURATION)),
  transition('dark-warning => dark-error',  animate(FLASH_DURATION)),
  transition('dark-error => dark-warning',  animate(FLASH_DURATION))
]);

上面的动画被定义在一个抽象的超类中,以便具体的子类可以像这样使用它们:

@Component(
  selector: 'tbw-time-editor',
  animations: [BACKGROUND_ANIMATIONS],
  templateUrl: '../digit-sequence-editor/digit-sequence-editor.directive.html',
  styleUrls: ['../digit-sequence-editor/digit-sequence-editor.directive.scss', './time-editor.component.scss'],
  providers: [ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => TimeEditorComponent), multi: true ,
               provide: NG_VALIDATORS, useExisting: forwardRef(() => TimeEditorComponent), multi: true ]
)
export class TimeEditorComponent extends DigitSequenceEditorDirective<number> implements OnInit 
  ...

首先,我希望将显示状态的数量减半。我认为必须拥有所有这些dark_-prefixed 状态是一种黑客行为。我宁愿让这些颜色自动更新,就像它们对 DOM 元素所做的那样,只需将 tbw-dark-mode 类添加到我的 HTML 文档的正文中即可。

我也仅限于支持两种预定义模式,明暗模式。用户可以自定义亮模式和暗模式,但第三种模式或通用“皮肤”是不可能的。

时间也很重要。这些颜色在嵌入我的组件的应用程序初始化期间生成一次,我看不到对允许稍后更新这些状态定义的 Angular API 的访问。

getBackgroundColor() 函数至少允许我在启动时检查颜色是如何定义的,但它并不完美(ios Safari 搞砸了,认为一切都是透明的),所以我必须定义固定的后备值无法从样式表更新。

我确实发现了一个令人作呕的 hack 来获得一些颜色的动态更新,但这不是我想要依赖的东西!我没有为每种颜色使用一个字符串,而是定义了一个动态颜色对象,如下所示:

class DynamicColor extends String 
  constructor(private colorKey: string) 

  // ...

  toString(): string 
    return this.colorTable[colorKey];
  

即使这需要对string 进行强制类型强制转换,并强制刷新屏幕以使更改生效。

有没有更好的方法?一种使用 CSS 类而不是静态定义样式的方法?我还没有找到更新 @Component 装饰器安装的动画的 API?

【问题讨论】:

【参考方案1】:

为什么不使用 CSS 变量来表示颜色?

https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties

然后您可以在状态动画中将背景颜色从--color-1 更改为--color-2

在应用程序的单独部分中,您可以使用以下方式更改这些变量的定义:

@Component( /*…*/ )
export class MyComponent 
  @HostBinding("style.--color-1")
  private color1: string;

  changeColor1(value: string) 
   this.color1 = value;
  

注意: 对 CSS 变量的支持很好,只要你不需要支持 IE:https://caniuse.com/css-variables

【讨论】:

当我深入研究 Angular 代码的内部时,这些颜色分配归结为这行代码:element.style[camelProp] = styles[prop];。以这种方式设置颜色时,没有适当的机制来解释 CSS 变量。这是在样式表级别完成的。只有具体定义的颜色才能在上面的代码中起作用。

以上是关于如何让 Angular 组件动画跟随 CSS 类的变化,而不是静态样式?的主要内容,如果未能解决你的问题,请参考以下文章

路由组件的Angular 2“动画幻灯片”

小程序 纯css 实现tab导航栏下划线跟随动画

Angular 4同时为父组件和子组件设置动画

Animate.css 和 Angular 4

让View跟随状态动起来——StateListAnimator

用于淡入和淡出视图的 Angular 4 动画