14

我正在绑定一个滚动事件来捕获滚动并对其进行处理,我创建了如下指令:

所以我有一个简单的指令,除了:

      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
4

1 回答 1

12

我可以为您提供几个技巧来做到这一点:

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

我不确定这是正确的方法。也许它可以帮助你进步...... :)

更新:

关于这个问题的答案:Angular2 的变化没有更新视图给了我第三个解决方案的想法。第二种解决方案正在工作,因为窗口是在角度区域之外创建的。你不能这样做:

this.zone.runOutsideAngular(() => {
  this.renderer.listenGlobal( 'window' , 'scroll' , ()=> {
      console.log( 'scrolling' );
  } ); 
});

它不起作用,因为 this.renderer 是在角度区域内创建的。http://plnkr.co/edit/UKjPUxp5XUheooKuKofX?p=preview

我不知道如何创建一个新实例 Renderer(在我们的例子中是 DomRenderer),所以我只是在工作区之外创建了新实例 EventManager 并使用新实例 NgZone。

于 2016-05-19T09:05:15.330 回答