Die Änderungserkennung ist ein sehr wichtiger Teil von Angular, der darin besteht, die Synchronisierung zwischen dem Modell und der Ansicht aufrechtzuerhalten. Im täglichen Entwicklungsprozess müssen wir uns nicht mit der Änderungserkennung auskennen, da Angular uns dabei hilft, diesen Teil der Arbeit abzuschließen, sodass sich Entwickler mehr auf die Geschäftsimplementierung konzentrieren und die Entwicklungseffizienz und Entwicklungserfahrung verbessern können. Wenn Sie das Framework jedoch ausführlich nutzen oder leistungsstarken Code schreiben möchten, anstatt nur Funktionen zu implementieren, müssen Sie die Änderungserkennung verstehen. Dies kann uns helfen, das Framework besser zu verstehen, Fehler zu debuggen, die Leistung zu verbessern usw. [Verwandte Tutorial-Empfehlung: „Angular Tutorial“]
Schauen wir uns zunächst ein kleines Beispiel an.
Wenn wir auf die Schaltfläche klicken, wird das Namensattribut geändert und das DOM wird automatisch mit dem neuen Namenswert aktualisiert.
Jetzt gibt es eine Frage: Wenn ich den Wert von name ändere und dann den innerText im DOM ausgebe, welchen Wert hat er?
import { Component, ViewChild, ElementRef } from '@angular/core'; @Component({ selector: 'my-app', templateUrl: './app.component.html', styleUrls: [ './app.component.css' ] }) export class AppComponent { name = 'Empty'; @ViewChild('textContainer') textContainer: ElementRef; normalClick(): void { this.name = 'Hello Angular'; console.log(this.textContainer.nativeElement.innerText); } }
Hast du richtig geantwortet?
Was genau passiert also in diesen beiden Codeteilen?
Wenn wir zum Schreiben dieses Codes natives JS verwenden, ändert sich die Ansicht nach dem Klicken auf die Schaltfläche definitiv nicht, aber die Ansicht ändert sich in Angular. Warum wird die Ansicht dann automatisch aktualisiert? Dies ist untrennbar mit einer Bibliothek namens zone.js verbunden. Vereinfacht gesagt führt sie eine Verarbeitung von Ereignissen durch, bei denen sich Werte ändern. Dies wird zunächst im Detail erläutert.
Wenn ich nicht möchte, dass diese Bibliothek diese Verarbeitung durchführt, bietet uns Angular auch eine Möglichkeit, zone.js zu deaktivieren.
Sie können zone.js in main.ts deaktivieren.
import { enableProdMode } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { AppModule } from './app/app.module'; import { environment } from './environments/environment'; if (environment.production) { enableProdMode(); } platformBrowserDynamic().bootstrapModule(AppModule, { ngZone: 'noop' }) .catch(err => console.error(err));
Wenn wir zone.js deaktivieren, wird die Ansicht nicht aktualisiert. Gehen Sie zum Quellcode, um den relevanten Code für die Ansichtsaktualisierung zu finden.
*/ class ApplicationRef { /** @internal */ constructor(_zone, _injector, _exceptionHandler, _initStatus) { this._zone = _zone; this._injector = _injector; this._exceptionHandler = _exceptionHandler; this._initStatus = _initStatus; /** @internal */ this._bootstrapListeners = []; this._views = []; this._runningTick = false; this._stable = true; this._destroyed = false; this._destroyListeners = []; /** * Get a list of component types registered to this application. * This list is populated even before the component is created. */ this.componentTypes = []; /** * Get a list of components registered to this application. */ this.components = []; this._onMicrotaskEmptySubscription = this._zone.onMicrotaskEmpty.subscribe({ next: () => { this._zone.run(() => { this.tick(); }); } }); ... } /** * Invoke this method to explicitly process change detection and its side-effects. * * In development mode, `tick()` also performs a second change detection cycle to ensure that no * further changes are detected. If additional changes are picked up during this second cycle, * bindings in the app have side-effects that cannot be resolved in a single change detection * pass. * In this case, Angular throws an error, since an Angular application can only have one change * detection pass during which all change detection must complete. */ tick() { NG_DEV_MODE && this.warnIfDestroyed(); if (this._runningTick) { const errorMessage = (typeof ngDevMode === 'undefined' || ngDevMode) ? 'ApplicationRef.tick is called recursively' : ''; throw new RuntimeError(101 /* RuntimeErrorCode.RECURSIVE_APPLICATION_REF_TICK */, errorMessage); } try { this._runningTick = true; for (let view of this._views) { view.detectChanges(); } if (typeof ngDevMode === 'undefined' || ngDevMode) { for (let view of this._views) { view.checkNoChanges(); } } } catch (e) { // Attention: Don't rethrow as it could cancel subscriptions to Observables! this._zone.runOutsideAngular(() => this._exceptionHandler.handleError(e)); } finally { this._runningTick = false; } } }
Umfassende Interpretation: Diese ApplicationRef ist eine Instanz der gesamten Angular-Anwendung. Im Konstruktor ist zone (Zonenbibliothek) onMicrotaskEmpty (dem Namen nach ist es ein Subjekt, das Mikroaufgaben löscht). einmal abonniert. Im Abonnement wird tick() aufgerufen, was wird also im Tick gemacht?
Denken:Ich habe letztes Mal gesagt, dass es am besten ist, den Konstruktor nicht zu abonnieren. Warum ist es hier so unregelmäßig? Natürlich nicht. Letztes Mal haben wir darüber gesprochen, welche Angular-Komponenten in
constructorund welche in ngOnInit platziert werden sollten. Aber hier ist ApplicationRef ein Dienst, daher kann der Initialisierungscode nur in constructor platziert werden. Wenn in der Tick-Funktion festgestellt wird, dass die Tick-Funktion ausgeführt wird, wird eine Ausnahme ausgelöst, da es sich um eine Instanz der gesamten Anwendung handelt und nicht rekursiv aufgerufen werden kann. Dann werden alle Ansichten durchlaufen und dann führt jede Ansicht
detectChanges() aus, was bedeutet, dass die Änderungserkennung ausgeführt wird. Was eine Änderungserkennung ist, wird später ausführlich erläutert. Wenn es sich dann um devMode handelt, durchlaufen Sie alle Ansichten erneut und jede Ansicht führt checkNoChanges() aus, um zu überprüfen, ob Änderungen vorliegen. Wenn es Änderungen gibt, wird ein Fehler ausgegeben (Ich werde später ausführlich auf dieses Problem eingehen , überspringe es vorerst) . Okay, jetzt weiß ich, wie ich es aktualisieren kann, nämlich die
tick-Methode von ApplicationRef aufzurufen. Lassen Sie es uns kurz klären. Das Update von DOM basiert auf dem Auslösen von zone.js und hilft Entwicklern, diesen Vorgang manuell auszulösen. Okay, jetzt können Sie zone.js aktivieren. Was ist also Änderungserkennung? Seien Sie weiterhin gespannt auf den nächsten Artikel. Programmierlehre Das obige ist der detaillierte Inhalt vonEine kurze Analyse des DOM-Aktualisierungsmechanismus bei der Erkennung von Winkeländerungen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!import { Component, ViewChild, ElementRef, ApplicationRef } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
name = 'Empty';
@ViewChild('textContainer') textContainer: ElementRef = {} as any;
constructor(private app: ApplicationRef){}
normalClick(): void {
this.name = 'Hello Angular';
console.log(this.textContainer.nativeElement.innerText);
this.app.tick();
}
}