我正在绑定一个滚动事件来捕获滚动并用它做一些事情,我已经创建了一个像bellow一样的指令:
所以我有简单的指令,只有:
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
答案 0 :(得分:11)
我可以为你提供几个黑客:
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' );
});
});
plunkr在这里http://plnkr.co/edit/jXBlM4fONKSNc7LtjChE?p=preview
我不确定这是正确的做法。也许它可以帮助你推进... :)
<强>更新强>
回答这个问题:View is not updated on change in Angular2给了我第三个解决方案的想法。 第二种解决方案是有效的,因为窗口是在角度区域之外创建的。你做不到:
this.zone.runOutsideAngular(() => {
this.renderer.listenGlobal( 'window' , 'scroll' , ()=> {
console.log( 'scrolling' );
} );
});
它不起作用,因为this.renderer是在角度区域内创建的。 http://plnkr.co/edit/UKjPUxp5XUheooKuKofX?p=preview
我不知道如何创建一个新的实例渲染器(在我们的例子中是DomRenderer)所以我只是在工作区之外创建了新的实例EventManager并使用新的实例NgZone。