防止本机浏览器事件(如滚动)触发更改检测
Prevent a native browser event ( like scroll ) from firing change detection
我绑定了一个滚动事件来捕获滚动并用它做一些事情,我创建了一个指令,如下所示:
所以我有一个简单的指令,它只有:
constructor ( private el : ElementRef ,
private renderer : Renderer ) {
this.domAdapter = new browser.BrowserDomAdapter();
this.ruler = new Ruler( this.domAdapter );
}
ngAfterViewInit () : any {
this.renderer.listenGlobal( 'window' , 'scroll' , ()=> {
console.log( 'scrolling' );
} );
return undefined;
}
这工作正常,希望我能看到它在我的所有应用程序中触发滚动变化检测。
这是我的组件之一:
private aFunction () {
console.log( 'change detected !!!' );
}
我在某个组件的某处的模板中有 aFunction
:
<div>{{ aFunction() }}</div>
以前,aFunction
被解雇,只有当我更新了一些输入或点击了一个按钮,但现在,它正在滚动进行变化检测!!!
因此,我的滚动体验很慢!
这是 Angular2 的正常行为,所有事件都应触发更改检测,但我想从该规则中排除我的滚动事件。
简而言之,如何在 Angular2 中定义事件并启用它触发更改检测的能力并使其成为手动的。
我正在寻找:
this.renderer.listenGlobalButDontFireTheChangeDetection
我可以为您提供几种技巧:
1) 只需在您的组件上将检测策略设置为 OnPush:
@Component({
...
changeDetection: ChangeDetectionStrategy.OnPush
})
对应的plunkr在这里http://plnkr.co/edit/NPHQqEmldC1z2BHFCh7C?p=preview
2) 使用 zone.runOutsideAngular 和原生 window.addEventListener:
this.zone.runOutsideAngular(() => {
window.addEventListener('scroll', (e)=> {
console.log( 'scrolling' );
});
});
另请参阅 plunkr http://plnkr.co/edit/6Db1AIsTEGAirP1xM4Fy
3) 将 zone.runOutsideAngular 与 EventManager 的新实例一起使用,如下所示:
import { DomEventsPlugin, EventManager } from '@angular/platform-browser';
...
this.zone.runOutsideAngular(() => {
const manager = new EventManager([new DomEventsPlugin()], new NgZone({enableLongStackTrace: false}));
manager.addGlobalEventListener('window','scroll', (e) => {
console.log( 'scrolling' );
});
});
笨蛋来了http://plnkr.co/edit/jXBlM4fONKSNc7LtjChE?p=preview
我不确定这是正确的方法。也许它可以帮助您前进... :)
更新:
这个问题的答案: 给了我第三种解决方案的想法。
第二种解决方案有效,因为 window 是在 angular 区域之外创建的。你不能只做:
this.zone.runOutsideAngular(() => {
this.renderer.listenGlobal( 'window' , 'scroll' , ()=> {
console.log( 'scrolling' );
} );
});
它不会工作,因为 this.renderer 是在 angular 区域内创建的。 http://plnkr.co/edit/UKjPUxp5XUheooKuKofX?p=preview
我不知道如何创建一个新的 Renderer 实例(在我们的例子中是 DomRenderer)所以我只是在工作区之外创建了一个新实例 EventManager 并使用了新实例 NgZone。
我绑定了一个滚动事件来捕获滚动并用它做一些事情,我创建了一个指令,如下所示:
所以我有一个简单的指令,它只有:
constructor ( private el : ElementRef ,
private renderer : Renderer ) {
this.domAdapter = new browser.BrowserDomAdapter();
this.ruler = new Ruler( this.domAdapter );
}
ngAfterViewInit () : any {
this.renderer.listenGlobal( 'window' , 'scroll' , ()=> {
console.log( 'scrolling' );
} );
return undefined;
}
这工作正常,希望我能看到它在我的所有应用程序中触发滚动变化检测。
这是我的组件之一:
private aFunction () {
console.log( 'change detected !!!' );
}
我在某个组件的某处的模板中有 aFunction
:
<div>{{ aFunction() }}</div>
以前,aFunction
被解雇,只有当我更新了一些输入或点击了一个按钮,但现在,它正在滚动进行变化检测!!!
因此,我的滚动体验很慢!
这是 Angular2 的正常行为,所有事件都应触发更改检测,但我想从该规则中排除我的滚动事件。
简而言之,如何在 Angular2 中定义事件并启用它触发更改检测的能力并使其成为手动的。
我正在寻找:
this.renderer.listenGlobalButDontFireTheChangeDetection
我可以为您提供几种技巧:
1) 只需在您的组件上将检测策略设置为 OnPush:
@Component({
...
changeDetection: ChangeDetectionStrategy.OnPush
})
对应的plunkr在这里http://plnkr.co/edit/NPHQqEmldC1z2BHFCh7C?p=preview
2) 使用 zone.runOutsideAngular 和原生 window.addEventListener:
this.zone.runOutsideAngular(() => {
window.addEventListener('scroll', (e)=> {
console.log( 'scrolling' );
});
});
另请参阅 plunkr http://plnkr.co/edit/6Db1AIsTEGAirP1xM4Fy
3) 将 zone.runOutsideAngular 与 EventManager 的新实例一起使用,如下所示:
import { DomEventsPlugin, EventManager } from '@angular/platform-browser';
...
this.zone.runOutsideAngular(() => {
const manager = new EventManager([new DomEventsPlugin()], new NgZone({enableLongStackTrace: false}));
manager.addGlobalEventListener('window','scroll', (e) => {
console.log( 'scrolling' );
});
});
笨蛋来了http://plnkr.co/edit/jXBlM4fONKSNc7LtjChE?p=preview
我不确定这是正确的方法。也许它可以帮助您前进... :)
更新:
这个问题的答案:
this.zone.runOutsideAngular(() => {
this.renderer.listenGlobal( 'window' , 'scroll' , ()=> {
console.log( 'scrolling' );
} );
});
它不会工作,因为 this.renderer 是在 angular 区域内创建的。 http://plnkr.co/edit/UKjPUxp5XUheooKuKofX?p=preview
我不知道如何创建一个新的 Renderer 实例(在我们的例子中是 DomRenderer)所以我只是在工作区之外创建了一个新实例 EventManager 并使用了新实例 NgZone。