【问题标题】:Angular: How to temporarily highlight dom elements that have just changed?Angular:如何临时突出显示刚刚更改的 dom 元素?
【发布时间】:2017-10-17 22:30:34
【问题描述】:

在我自己实施解决方案之前,我想知道当数据绑定的属性值刚刚改变时,是否有一种简单的方法可以改变元素的样式(简短的突出显示)。

我的 DOM 中有很多元素,所以我不想在组件中存储和维护专用属性。

我要突出显示的元素是传统输入表单的元素:

    <tr field label="Lieu dépôt">
        <select class="cellinput" #lieuDepotBon [(ngModel)]="rapport.LieuDepotBon" (ngModelChange)="changeRapport({LieuDepotBon:$event})">
            <option [ngValue]="null"></option>
            <option [ngValue]="i" *ngFor="let depotBonChoice of DepotBonInterventionValues; let i = index">{{DepotBonIntervention[i]}}</option>
        </select>
    </tr>
    <tr field *ngIf="rapport.LieuDepotBon==DepotBonIntervention.Autre" label="Autre lieu">
        <input class="cellinput" #autreLieuDepotBon [(ngModel)]="rapport.AutreLieuDepotBon" (ngModelChange)="changeRapport({AutreLieuDepotBon:autreLieuDepotBon.value})" />
    </tr>

我听说过 Angular2 使用 ngModel 指令在元素上设置的特殊类样式可以帮助完成我需要的操作,但我找不到更多相关信息。

【问题讨论】:

  • 这个问题只针对input 元素吗? changed 是什么意思? 我听说 Angular2 设置了特殊的类样式 - 你的意思是 ng-dirty 类吗?如果是这样,请尝试简单地为input.ng-dirty {background-color: green}添加样式
  • 它特定于带有 ngModel 指令的元素。似乎 ng-dirty/ng-touched 没有提供解决方案,因为它们依赖于用户对控件的操作。在我的情况下,更改不是由用户执行的。这只是数据模型的变化。
  • 在我的情况下,更改不是由用户执行的。 - 你能举个例子吗?
  • 更改是通过数据结构的合并来执行的,我为此使用了 lodash。这是一个示例 Lodash.merge(updatedInter, newData)。我的表单控件绑定到那些合并结构的一些数据。
  • 好吧,也许你可以装个简单的小工具?

标签: css angular typescript controlvalueaccessor


【解决方案1】:

要暂时突出显示 DOM 元素,请使用 setTimeout() 添加或删除 CSS 类

check demo

HTML

<mat-form-field [ngClass]="{'changed': isChanged}">
  <mat-select [(ngModel)]="yourModel" (ngModelChange)="modelChanged($event)">
     <mat-option value="1">1</mat-option>
     <mat-option value="2">2</mat-option>
     <mat-option value="3">3</mat-option>
  </mat-select>
</mat-form-field>

打字稿

isChanged: boolean = false
modelChanged(value) {
   console.log('model changed')

   this.isChanged = true
   setTimeout(() => {
       this.isChanged = false
   }, 1000);
}

CSS

.changed {
    transition: color 0.4s ease-in, text-shadow 0.4s ease-in, background-color 0.5s linear 0s;
    text-shadow: #bbb 2px 2px 2px;
    background-color: #ffffcc;
    color: #BF1722;
}

注意:如果您的应用程序以毫秒为单位发生变化,那么您应该将setTimeout() 的时间减少到 0.5s0.3s您的申请要求。

感谢 Ingo Bürk 指出这个问题

【讨论】:

  • 当有多个更新出现时,这将严重崩溃。
  • 你能解释一下会发生什么类型的可怕故障吗?
  • 如果同时有3个updates会更新第一个,等待1s,触发第二个,等待1s,触发第三个
  • 当一个元素被更新时,它会突出显示该元素1s,以便用户显示更新成功。
  • 我认为您误解了或者我不理解您的观点。如果你可以修改,请做,让它变得更好,我想向你学习。如何让用户更好地指示更改成功
【解决方案2】:

这是我的解决方案。

我想突出显示表单中被其他用户实时更改的数据。

在我的 HTML 表单中,我用 Angular 组件替换了原生 html 元素。对于每种类型的原生元素,我都创建了一个支持 Highlight 的新 Angular 组件。每个组件都实现了 ControlValueAccessor Angular 接口。

在父表单中我替换了原生元素:

<input [(ngModel)]="itinerary.DetailWeather" />

通过我的自定义元素:

<reactive-input [(ngModel)]="itinerary.DetailWeather"></reactive-input>

当 Angular 为父表单调用 detectChanges() 时,它会检查表单组件用作输入的所有数据。

如果一个组件是一个 ControlValueAccessor,并且在应用程序模型中发生了变化,它会调用方法 ControlValueAccessor.writeValue(value)。它是当内存中的数据发生变化时调用的方法。我用它作为一个钩子来临时更新样式以添加高亮。

这是自定义元素。我使用 Angular Animations 来更新边框颜色并淡化回原始颜色。

import { Component, Input, forwardRef, ChangeDetectorRef } from '@angular/core';
import { ControlValueAccessor,  NG_VALUE_ACCESSOR  } from '@angular/forms';
import { trigger, state, style, animate, transition, keyframes } from '@angular/animations';

@Component(
{
  selector: 'reactive-input',
  template: `<input class="cellinput" [(ngModel)]="value" [@updatingTrigger]="updatingState" />`,
  styles: [`.cellinput {  padding: 4px }`],
  animations: [
    trigger( 
      'updatingTrigger', [
        transition('* => otherWriting', animate(1000, keyframes([
          style ({ 'border-color' : 'var( --change-detect-color )', offset: 0 }),
          style ({ 'border-color' : 'var( --main-color )', offset: 1 })
        ])))
    ])
  ],
  providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => ReactiveInputComponent), multi: true } ]
})
export class ReactiveInputComponent implements ControlValueAccessor {

  public updatingState : string = null;
  _value = '';

  // stores the action in the attribute (onModelChange) in the html template:
  propagateChange:any = ( change ) => {};

  constructor( private ref: ChangeDetectorRef ) { }

  // change from the model
  writeValue(value: any): void
  {
    this._value = value; 
    this.updatingState = 'otherWriting';

    window.setTimeout( () => {
      this.updatingState = null;
    }, 100 );

    // model value has change so changes must be detected (case ChangeDetectorStrategy is OnPush)
    this.ref.detectChanges();
  }

  // change from the UI
  set value(event: any)
  {
    this._value = event;
    this.propagateChange(event);
    this.updatingState = null;
  }

  get value()
  {
    return this._value;
  }

  registerOnChange(fn: any): void { this.propagateChange = fn; }
  registerOnTouched(fn: () => void): void {}
  setDisabledState?(isDisabled: boolean): void {};
}

【讨论】:

    【解决方案3】:

    我能想到的最简单、更简洁的方法是像这样实现 2 个 css 类:

    .highlight{
        background-color: #FF0;
    }
    .kill-highlight{
        background-color: #AD310B;
        -webkit-transition: background-color 1000ms linear;
        -ms-transition: background-color 1000ms linear;
        transition: background-color 1000ms linear;
    }
    

    然后依次影响这两个元素。 希望对你有帮助

    【讨论】:

    • 更准确地说,我的问题是关于如何在模型发生更改时影响 css 类。我会发布一个解决方案。
    猜你喜欢
    • 2013-04-13
    • 1970-01-01
    • 1970-01-01
    • 2013-12-05
    • 2018-04-16
    • 1970-01-01
    • 2010-11-15
    • 2018-02-03
    • 2011-01-27
    相关资源
    最近更新 更多