ブラウザのスクロール位置を追跡し、それについて複数のコンポーネントを通知する簡単な方法はありますか?
使用例:スクロール時に、現在の場所に基づいてページ上のさまざまな要素のクラスを変更できるようにします。 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>
そして今、アプリは完全に空の画面でロードされます。楽しい楽しい楽しい...
最終的な解決策(それは私のために働いた)。
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);
}
}
directives: [TrackScrollDirective]
<div class="col-md-12" track-scroll>
一番簡単な方法は、関心のある各コンポーネントがスクロールイベントをリッスンすることだと思います。
@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 );
}
}
ヒント:
bootstrap(MyComponent, [
provide(PLATFORM_DIRECTIVES, {useValue: [TrackScrollDirective], multi:true})]);
すべてのコンポーネントdirective: [...]
リストに追加せずに、ディレクティブをユニバーサルにします。
ウィンドウ上でいくつかのスクロール要素を見る必要があるため、これを別の方法で解決せざるを得ませんでした。要素のスクロール位置を監視するディレクティブを作成しました。
@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()
}
}
angularドキュメントプロジェクトの一部として、 ScrollService のソースを確認します。
彼らが位置を取得する方法はfromEvent(window, 'scroll')
次に、コンポーネントに注入するグローバルサービスで次のようなことを実行できます。
public readonly windowScroll$ = fromEvent(window, 'scroll').pipe(map(x => window.scrollY), startWith(0), distinctUntilChanged(), shareReplay(1));
startWith(0)
が必要なのは、実際にスクロールするまでスクロールイベントを取得できない場合があるためです。必要に応じてデバウンスを追加できます。