Предотвращение события собственного браузера (например, прокрутки) от обнаружения смены огня

Я привязываю событие прокрутки, чтобы захватить прокрутку и сделать что-то с ней, я создал директиву, подобную приведенной ниже:

Итак, у меня есть простая директива, которая имеет только:

      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

Я могу предложить вам несколько хакеров, чтобы сделать это:

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

Я не уверен, что это правильный подход. Может быть, это поможет вам в продвижении...:)

Update:

Ответ на этот вопрос: Просмотр не обновлен при изменении Angular2, дал мне идею для третьего решения. Второе решение работает, потому что окно было создано вне зоны 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.