跟踪滚动位置并通知其他组件

Shu*_*sky 45 events scroll typescript 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

在app的主指令中添加了一个属性:

<priz-app track-scroll>
Run Code Online (Sandbox Code Playgroud)

并将该组件添加为顶级组件中的提供者之一:

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]
})
Run Code Online (Sandbox Code Playgroud)

依然没有...


另一个更新:

移动track-scroll到主模板的div元素之一:

<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>
Run Code Online (Sandbox Code Playgroud)

现在,应用程序加载了一个完全空的屏幕.FUN FUN FUN ...


最终解决方案(对我有用).

  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);
    }
}
Run Code Online (Sandbox Code Playgroud)
  1. 将它添加为使用它的所有地方的指令:
directives: [TrackScrollDirective]
Run Code Online (Sandbox Code Playgroud)
  1. 将属性添加到我们要跟踪事件的每个元素:
<div class="col-md-12" track-scroll>
Run Code Online (Sandbox Code Playgroud)

Gün*_*uer 58

我认为最简单的方法是每个感兴趣的组件都在监听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 );
    }
  }
Run Code Online (Sandbox Code Playgroud)

plunker

使用的Plunker @HostListener()

暗示:

bootstrap(MyComponent, [
    provide(PLATFORM_DIRECTIVES, {useValue: [TrackScrollDirective], multi:true})]);
Run Code Online (Sandbox Code Playgroud)

使指令通用,而不将其添加到每个组件directive: [...]列表.

  • 对于浏览器交叉兼容性,请使用window.pageYOffset而不是document.body.scrollTop,请参阅https://developer.mozilla.org/en-US/docs/Web/API/Window/pageYOffset和https://developer.mozilla .ORG/EN-US /文档/网络/ API /窗/ scrollY (3认同)
  • 顺便说一句,带有`HostListener` 的选项由于某种原因不起作用。没有花时间深入研究它。 (2认同)

Nat*_*May 12

我被迫以不同的方式解决这个问题,因为我需要观察窗口上的几个滚动元素。我创建了一个指令来观察元素上的滚动位置:

@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 }
}
Run Code Online (Sandbox Code Playgroud)

然后在任何包含需要此元素的滚动元素的任何组件上,我都可以使用@ViewChild如下指令:

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

  @ViewChild(ScrollDir) scroll: ScrollDir;

  ngAfterViewChecked() {
    this.scroll.reset()
  }
}
Run Code Online (Sandbox Code Playgroud)


Sim*_*ver 8

查看ScrollService的源代码,作为 angular 文档项目的一部分。

他们获得职位的方式是 fromEvent(window, 'scroll')

然后,您可以在注入到组件中的全局服务中执行以下操作:

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

startWith(0)是必需的,因为在您实际滚动之前您可能不会获得滚动事件。如果需要,您可以添加去抖动。