根据我的理解runOutsideAngular(),如果我需要运行一些不会触发Angular变化检测的东西,我需要使用这个函数.但是,我的代码不起作用; 当我单击按钮时,UI正在变化,数字为2.
@Component({selector: 'my-cmp',
template: `<h1>{{num}}</h1>
<button (click)="onClick()">Change number</button>`})
class MyComponent implements OnChanges {
num = 1;
constructor(private _ngZone: NgZone ) {
}
onClick() {
this._ngZone.runOutsideAngular(() => {
this.num = 2;
}}));
}
}
Run Code Online (Sandbox Code Playgroud)
Gün*_*uer 13
如果有任何事情导致更改检测,并且绑定事件(click)="onClick()"确实会导致更改检测,则Angular将检测更改.
runOutsideAngular 并不意味着Angular不会看到更改,它只意味着以这种方式运行的代码不会导致更改检测,但由于click事件已经发生,因此在您的示例中它没有意义.
如果您想阻止更改检测,那么您可以
1)订阅ngZone.onMicrotaskEmpty如下:
import { NgZone, ChangeDetectorRef } from '@angular/core';
import 'rxjs/add/operator/first';
...
export class MyComponent {
constructor(private ngZone: NgZone, private cdRef: ChangeDetectorRef) {}
onClick() {
// to do something
this.cdRef.detach();
this.ngZone.onMicrotaskEmpty.first().subscribe(() => {
// reattach changeDetector after application.tick()
this.cdRef.reattach();
});
}
}
Run Code Online (Sandbox Code Playgroud)
此处理程序将在之后运行 Application.tick
2)使用这样的自定义指令:
@Directive({
selector: '[outSideEventHandler]'
})
class OutSideEventHandlerDirective {
private handler: Function;
@Input() event: string = 'click'; // pass desired event
@Output('outSideEventHandler') emitter = new EventEmitter();
constructor(private ngZone: NgZone, private elRef: ElementRef) {}
ngOnInit() {
this.ngZone.runOutsideAngular(() => {
this.handler = $event => this.emitter.emit($event);
this.elRef.nativeElement.addEventListener(this.event, this.handler);
});
}
ngOnDestory() {
this.elRef.nativeElement.removeEventListener(this.event, this.handler);
}
}
Run Code Online (Sandbox Code Playgroud)
然后在模板中你可以写:
<button (outSideEventHandler)="onClick()">Click outside zone</button>
Run Code Online (Sandbox Code Playgroud)
要么
<button event="mousedown" (outSideEventHandler)="onClick()">Click outside zone</button>
Run Code Online (Sandbox Code Playgroud)
3)编写自定义DOM事件处理程序,如本文所述.
其他解决方案见:
[简而言之]您需要在当前代码中更改一行
onClick() {
this._ngZone.runOutsideAngular(() => {
setTimeout(()=>this.num = 2,0); // instead of this.num = 2;
}}));
}
Run Code Online (Sandbox Code Playgroud)
现在,如果单击上<button>,this.num将成为2,但您将看不到UI中的任何更改(视图和模型之间的临时不一致)
[说明]没有runOutsideAngular(),异步函数喜欢addEventListener()或setTimeout()表现不同(猴子修补).他们的回调将在运行用户代码后尝试使用Angular更新UI.例如,您可以(click)="onClick()"视为:
addEventListener("click",function modifiedCallback(){
onClick();
updateUIifModelChanges(); //call to Angular
})
Run Code Online (Sandbox Code Playgroud)
为了不触发UI更新,我们需要满足以下两个条件:
onClick(所以,在里面修改setTimeout())updateUIifModelChanges(调用setTimeout()内runOutsideAngular)[更多]原因,我给出的解释是一个非常非常简化的版本.setTimeout()具有相同的功能签名,无论它是否在内部运行runOutsideAngular().它表现不同的原因是因为它在不同的区域中运行
使用ngZone.run比解决方案好一点,setTimeout因为它使用角度特定功能。Run 旨在在ngZone.runOutsideAngular函数内使用。
来自文档:
通过 run 运行函数允许您从在 Angular 区域之外执行的任务(通常通过 {@link #runOutsideAngular} 启动)重新进入 Angular 区域。
这实际上是一个非常实际的示例,例如一个按钮将数字加一,但仅在数字为偶数时触发更改检测。
@Component({selector: 'my-cmp',
template: `<h1>{{num}}</h1>
<button (click)="onClick()">Change number</button>`})
class MyComponent implements OnChanges {
num = 1;
constructor(private _ngZone: NgZone ) {
}
onClick() {
this._ngZone.runOutsideAngular(() => {
if(this.num % 2 === 0){
// modifying the state here wont trigger change.
this.num++;
} else{
this._ngZone.run(() => {
this.num++;
})
}
}}));
}
}Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
10783 次 |
| 最近记录: |