Angular 2点击事件回调而不触发变化检测

标签 angular angular2-changedetection zonejs

我在尝试在 (click) 中执行某些逻辑时遇到了很大的麻烦Angular 2 中的事件回调函数,不会触发更改检测。

为什么我不想触发变化检测

回调函数执行简单的动画滚动到顶部。它不影响其他组件,因此我不需要更改检测来触发每个组件,事实上我真的不希望它触发!由于变化检测确实在每个组件中触发,因此移动设备上的动画性能极差。

我尝试过的

我知道我可以使用

在区域外运行代码
this._zone.runOutsideAngular(() => {
    someFunction();
})

当您要在区域外运行的代码未被 click 调用时,这会很好地工作, keyup , keydown事件等

因为我的组件看起来像...

<button (click)="doThing()">Do that thing outside the zone!</button>

doThing() {
    this._zone.runOutsideAngular(() => {
        myFunction();
    })
}

... myFunction将在区域外运行,但 click事件将触发变化检测。

我已经实现了 OnPush尽可能多地更改我的组件中的检测策略。

这里不触发变更检测很重要,但我找不到阻止它的方法。

编辑 看这个plnk更改检测设置为 OnPush在所有组件中。单击子行组件按钮会触发子行、行和应用程序组件中的 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 手动绑定(bind)到我想要的任何事件,在本例中是点击,使用 fromEvent。此示例还演示了清理事件订阅的做法。

import { Component, ElementRef, OnInit, OnDestroy, NgZone } from '@angular/core';
import { takeUntil } from "rxjs/operators";
import { Subscription, fromEvent, Subject } from 'rxjs';

@Component({
    selector: 'test'
    template: `<button #myButton>Click me</button>`,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class MyComponent implements OnInit {

    private _destroyed$: Subject<null> = new Subject();

    // reference to template variable
    @ViewChild('myButton') myButton: ElementRef<HTMLButtonElement>;

    constructor(private _zone: NgZone){}

    ngOnInit() {
        this.subscribeToMyButton();
    }

    subscribeToMyButton() {
        this._zone.runOutsideAngular(() => {
            fromEvent(this.myButton.nativeElement, 'click')
                .pipe(takeUntil(this._destroyed$))
                .subscribe(e => {
                    console.log('Yayyyyy! No change detection!');
                });
        });
    }

    ngOnDestroy() {
        // clean up subscription
        this._destroyed$.next();
        this._destroyed$.complete();
    }

}

希望这对处于类似情况的其他人有所帮助。

关于Angular 2点击事件回调而不触发变化检测,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39729846/

相关文章:

http - RxJS 和 AngularJS HTTP - 我怎样才能做到这一点?

具有所选属性的 Angular 选择选项不起作用

html - Angular 5 - 带 firebase 的异步管道

angular - 在 Angular 中导入 @ngrx/core @ngrx/store 时出现问题

Angular 2 + OnPush : Change detection does not work on pouchdb callbacks

angular - 在 Angular2 中登录后刷新标题

angular - 导航在 Angular 区域外触发,您是否忘记调用 'ngZone.run()' ?

javascript - 修补 Element.prototype.addEventListener 会破坏任何 Angular 2 应用程序

angular - Angular 是否有 React 的 Virtual DOM 的等价物?

javascript - 为什么即使设置了 OnPush 标志,Angular2 在更改检测期间也会捕获引用更改和原始更改?