web-dev-qa-db-ja.com

スクロール位置を追跡し、それについて他のコンポーネントに通知する

ブラウザのスクロール位置を追跡し、それについて複数のコンポーネントを通知する簡単な方法はありますか?

使用例:スクロール時に、現在の場所に基づいてページ上のさまざまな要素のクラスを変更できるようにします。 angularの以前のバージョンでは、プラグイン(jQueryでも同じ)を使用していくぶん可能でした。もちろん、アプリケーションの起動時に初期化してイベントを発行するために、ベアJSを作成するオプションがありますが、それは汚いように聞こえます。

ここで私のオプションは何ですか?


更新(提案後):

ここに私が試したものがあります:

コンポーネントを作成しました:

import {Component} from "angular2/core";

@Component({
    selector: '[track-scroll]',
    Host: {'(window:scroll)': 'track($event)'},
    template: ''
})

export class TrackScrollComponent {
    track($event) {
        console.debug("Scroll Event", $event);
    }
}

アプリのメインディレクティブに属性を追加しました。

<priz-app track-scroll>

そして、コンポーネントを最上位コンポーネントのプロバイダーの1つとして追加しました。

import {TrackScrollComponent} from "../../shared/components/track-scroll.component";

@Component({
  selector: 'priz-app',
  moduleId: module.id,
  templateUrl: './app.component.html',
  directives: [ROUTER_DIRECTIVES, SecureRouterOutlet, AppHeader, TrackScrollComponent],
  providers: [AuthenticationService]
})

まだ何も...


別の更新:

track-scrollをメインテンプレートのdiv要素の1つに移動しました。

<div class="container-fluid" track-scroll>
    <div class="row">
        <div class="col-md-12">
            <app-header></app-header>
            <secure-outlet signin="Login" unauthorized="AccessDenied"></secure-outlet>
        </div>
    </div>
</div>

そして今、アプリは完全に空の画面でロードされます。楽しい楽しい楽しい...


最終的な解決策(それは私のために働いた)。

  1. ディレクティブを定義します。
import {Directive} from "angular2/core";

@Directive({
    selector: '[track-scroll]',
    Host: {'(window:scroll)': 'track($event)'}
})

export class TrackScrollDirective {
    track($event: Event) {
        console.debug("Scroll Event", $event);
    }
}
  1. それを使用するすべての場所にディレクティブとして追加します。
directives: [TrackScrollDirective]
  1. イベントを追跡する各要素に属性を追加します。
<div class="col-md-12" track-scroll>
44

一番簡単な方法は、関心のある各コンポーネントがスクロールイベントをリッスンすることだと思います。

  @Component({
    ...
    // alternative to `@HostListener(...)`
    // Host: {'(window:scroll)': 'doSomething($event)'}
  })
  class SomeComponent {
    @HostListener('window:scroll', ['$event']) 
    doSomething(event) {
      // console.debug("Scroll Event", document.body.scrollTop);
      // see András Szepesházi's comment below
      console.debug("Scroll Event", window.pageYOffset );
    }
  }

plunker

@HostListener()を使用したプランカー

ヒント:

bootstrap(MyComponent, [
    provide(PLATFORM_DIRECTIVES, {useValue: [TrackScrollDirective], multi:true})]);

すべてのコンポーネントdirective: [...]リストに追加せずに、ディレクティブをユニバーサルにします。

58

ウィンドウ上でいくつかのスクロール要素を見る必要があるため、これを別の方法で解決せざるを得ませんでした。要素のスクロール位置を監視するディレクティブを作成しました。

@Directive({
  selector: '[scroll]'
})
export class ScrollDir {
  @Output() setScroll = new EventEmitter();
  private scroll: number;

  constructor(private el: ElementRef) { }

  @HostListener('scroll', ['$event'])
  scrollIt() { this.scroll = event.srcElement.scrollTop }

  reset() {  this.el.nativeElement.scrollTop = this.scroll }
}

次に、この要素を必要とするスクロール要素を含むコンポーネントで、次のようなディレクティブを@ViewChildできます:

@Component({
  selector: 'parent',
  template: `
    <div class="container" scroll>
      // *ngFor=""...
    </div>
  `
})
export class ParentComp implements AfterViewChecked {

  @ViewChild(ScrollDir) scroll: ScrollDir;

  ngAfterViewChecked() {
    this.scroll.reset()
  }
}
4
Nate May

angularドキュメントプロジェクトの一部として、 ScrollService のソースを確認します。

彼らが位置を取得する方法はfromEvent(window, 'scroll')

次に、コンポーネントに注入するグローバルサービスで次のようなことを実行できます。

public readonly windowScroll$ = fromEvent(window, 'scroll').pipe(map(x => window.scrollY), startWith(0), distinctUntilChanged(), shareReplay(1));

startWith(0)が必要なのは、実際にスクロールするまでスクロールイベントを取得できない場合があるためです。必要に応じてデバウンスを追加できます。

2
Simon_Weaver