Angular 2单击事件回调而不触发更改检测
我在尝试执行Angular 2中的(click)
事件回调函数内的某些逻辑时遇到了重大故障,而未触发更改检测。Angular 2单击事件回调而不触发更改检测
为什么我不想触发变化检测
回调函数执行简单的动画滚动到顶部。它不会影响其他组件,因此我不需要在每个组件中触发更改检测,事实上,我真的不希望它启动!由于变化检测在每个组件中都会触发,因此移动设备上的动画性能非常差。
我已经试过
我知道我可以使用区外运行的代码
this._zone.runOutsideAngular(() => {
someFunction();
})
当代码要运行的外部不调用区这很好地工作由click
,keyup
,事件等
因为我的组件看起来像......
<button (click)="doThing()">Do that thing outside the zone!</button>
doThing() {
this._zone.runOutsideAngular(() => {
myFunction();
})
}
... myFunction
将区外运行,但click
事件将触发变化检测。
我已经在尽可能多的组件中实现了OnPush
更改检测策略。
重要的是变化检测不会触发在这里,但我找不到防止它的方法。
编辑 看到这个plnk与变化检测中的所有组件设置为OnPush
。点击subrow组件按钮将在子行,行和应用程序组件中触发CD。
如上所述,即使设置在其中click
事件发生时将OnPush
仍然导致触发变化检测的组件。
出的现成事件处理
@Component({
selector: 'test'
template: `<button (click)="onClick($event)">Click me</button>`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class MyComponent {
onClick(e:Event) {
e.preventDefault();
e.stopPropagation();
this._zone.runOutsideAngular(() => {
// gets run outside of Angular but parent function still triggers change detection
});
return false;
/*
* change detection always triggered
* regardless of what happens above
*/
}
}
大部分的时间,这可能不是一个问题,但在渲染时和某些功能的绘画表现我走的方法至关重要完全绕过了Angular的内置事件处理。从我自己的实验中,以下似乎是解决这个问题的最简单和最可维护的方法。
绕道出的现成事件处理
的想法在这里是用RxJS点击手动绑定到我想要的任何事件,在这种情况下,使用Observable.fromEvent
。此示例还说明了清理事件订阅的做法。
import {Component, ElementRef, OnInit, OnDestroy, NgZone} from '@angular/core';
import {Observable} from 'rxjs/Observable';
import {Subscription} from 'rxjs/Subscription';
@Component({
selector: 'test'
template: `<button #myButton>Click me</button>`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class MyComponent implements OnInit {
private _subs:Subscription[] = [];
// reference to template variable
@ViewChild('myButton') myButton:ElementRef;
constructor(private _zone:NgZone){}
ngOnInit() {
this.manuallyBindToViewEvents();
}
manuallyBindToViewEvents() {
this.subscribeToMyButton()
}
subscribeToMyButton() {
let sub:Subscription;
this._zone.runOutsideAngular(() => {
sub = Observable.fromEvent(this.myButton.nativeElement, 'click').subscribe(e => {
console.log('Yayyyyy! No change detection!');
})
});
this._subs.push(sub);
}
ngOnDestroy() {
// clean up subscriptions
this._subs.forEach(sub => sub.unsubscribe());
}
}
希望这对于其他类似情况有所帮助。
如果使用
OnPush
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
})
然后更改检测应仅限于点击事件发生的组件。
您可以分离ChangeDetectorRef
constructor(private ref: ChangeDetectorRef, private dataProvider:DataProvider) {
ref.detach();
}
变化检测会,直到重新连接不被此组件运行。
我不确定是这种情况。我会用格式不正确的plnk编辑原始帖子! – garethdn
'detatch()'似乎阻止了变化检测https://plnkr.co/edit/wVjjGhcZkqVbtsVjvZyi?p=preview。 –
我也对事件尝试了'preventDefault()'和'stopPropagation()',但这并没有阻止变更检测在所有组件上运行。 –
我可以显示一个完整的黑客,但似乎它的工作。
子行组件。TS
constructor(private zone: NgZone, private app: ApplicationRef) {}
rowClick() {
console.log('rowClick');
var a = 4;
let originalTick = (<any>this.app).constructor.prototype.tick;
(<any>this.app).constructor.prototype.tick =() => console.info('tick tick tick :)');
const subscriber = this.zone.onMicrotaskEmpty.subscribe({
next:() => {
console.info('tick has been stopped. So we can return everything in its place');
subscriber.unsubscribe();
(<any>this.app).constructor.prototype.tick = originalTick;
}});
}
您是否尝试在该组件的@Component({})'装饰器中使用'changeDetection:ChangeDetectionStrategy.OnPush'? – micronyks