2
votes

La fonction de temps angulaire TimelineLite ne fonctionne pas avec OnInit

J'essaie d'implémenter une barre de progression et un minuteur en utilisant TimelineLite:

HTML:

<button (click)="start()">Start</button>

CSS:

ngOnInit() {
  setTimeout(() => this.start(), 3000);
}

 entrez la description de l'image ici

Voici ce que je veux:
Lorsque la page se charge, la barre de progression commence à s'animer de 100% à 0% de largeur (durée de 10 s). Je souhaite également afficher le résultat de la fonction time .
Voici ce que j'ai fait:

public timeline = new TimelineLite();

ngOnInit() {
  this.start();
}

start() {
  const progress = document.getElementById('progress');
  this.timeline.fromTo(progress, 10, {width: '100%'}, {width: 0, ease: Linear.easeNone});
}

Ainsi, lorsque la page se charge, la barre de progression fonctionne mais pas le minuteur. Je ne sais pas pourquoi. Si j'essaie de définir un délai d'expiration de 3 secondes à ngOnInit , cela fonctionne:

#progress {
  width: 100%;
  height: 30px;
  background-color: red;
}

Aussi si je crée un bouton, appelle start au clic, ça marche:

<div id="progress"></div>
{{timeline.time()}}

Donc le problème est que la minuterie ne fonctionne pas si j'essaye d'appeler fromTo fonction de ngOnInit.


2 commentaires

Cela fonctionne pour moi, comme vous pouvez le voir dans ce stackblitz . Dans cet autre stackblitz , je simule un cas où le div n'est pas présent initialement en raison d'une condition ngIf , comment vous pouvez détecter quand il est disponible, et appeler start à ce moment.


@ConnorsFan, oui, cela fonctionne sur StackBlitz, mais sur ma machine locale, ce n'est pas le cas. Pourriez-vous jeter un œil à mon référentiel github.com/BorisZubchenko/TimelineLiteTimer . Il contient un code identique.


3 Réponses :


0
votes

Il s'agit évidemment d'un cas de chronologie d'appels de méthodes de cycle de vie angulaire. Il est fort probable que le problème se situe dans onInit où vous n'obtenez pas immédiatement l'élément DOM progress . Vous l'avez fait pour fonctionner en appliquant settimeout , l'autre manière est de conserver un setinterval jusqu'à ce que vous trouviez progress .
Apparemment, le meilleur moyen est d'écrire this.start () dans ngAfterViewInit () au lieu de ngOnInit()


0 commentaires

0
votes

Cela se produit probablement parce que le délai d'expiration commence après l'initialisation du modèle, puis le code s'exécute, en dehors d'OnInit. Je ne suis pas sûr cependant.

Vous pouvez utiliser zone.run () ici.

Voici un lien, qui peut s'avérer utile pour vous: https://medium.com/@MertzAlertz/what-the-hell-is-zone-js-and-why-is- it-in-my-angular-2-6ff28bcf943e


0 commentaires

1
votes

Bonjour, vous devriez utiliser @ViewChild pour cibler vos éléments et utiliser AfterViewInit lifeCycleHook lorsque vous souhaitez manipuler | accès à votre DOMElement (composant actuel ou composant enfant).

this.timeline.eventCallback('onUpdate', () => {
  // angular is not inform by default than something happen here.
 }, [] );

Pour faciliter vos tests, j'ai fait Demande d'extraction Github . Quiconque a lu votre question d'origine peut facilement voir la différence.


Mise à jour 1: sur votre vue, vous appelez une fonction qui renvoie la minuterie actuelle de TimelineLite. Comme il ne s'agit que d'un appel de fonction, il ne sera pas appelé encore et encore à chaque mise à jour interne de TimelineLite.

Pour ce faire, vous devez utiliser Liaison d'événement TimelineLite .

Désormais, par défaut, votre vue ne sera pas "mise à jour" chaque fois que vous mettez à jour votre attribut à partir du code suivant:

export class AppComponent implements AfterViewInit {

  @ViewChild('progress') progressElement: ElementRef;

  constructor(private changeRef: ChangeDetectorRef) { } 

  public timeline = new TimelineLite();
  ngAfterViewInit() {
    this.start();
  }

  start() {
    this.timeline.eventCallback('onUpdate', () => {
      this.time = this.timeline.time();
      this.changeRef.detectChanges();
    }, [] );

    // Here i use the ViewChild Binding instead of pure javascript fetching.
    this.timeline.fromTo(this.progressElement.nativeElement, 10, {width: '100%'}, {width: 0, ease: Linear.easeNone});
  }
}

c'est pourquoi, vous devriez utiliser ChangeDetectorRef pour forcer angular à détecter l'attribut de composant mis à jour le plus récent.

extraction demandée mise à jour


2 commentaires

Salut, merci pour votre PR. Le problème est que la barre de progression fonctionne, mais pas le minuteur. Votre solution ne résout pas mon problème.


oh je vois, j'ai mis à jour mon post stackoverflow et ma pull request.