【问题标题】:Tracking scroll position and notifying other components about it跟踪滚动位置并通知其他组件
【发布时间】:2016-07-27 20:53:50
【问题描述】:

是否有一种简单的方法可以跟踪浏览器滚动位置并通知多个组件?

用例:在滚动时,我希望能够根据我所在的位置更改页面上各种元素的类别。在以前版本的 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>

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

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 元素之一:

<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>

【问题讨论】:

  • 下一个问题是,将其传播到另一个组件的最佳方式是什么?
  • 不确定您所说的传播是什么意思?您可以使用@Output() 发出并将其绑定到另一个组件的@Input()。我在我的回答中添加了关于 directives: [...] 的评论。
  • 基本上,我想在其他组件中使用此信息。我必须通过EventEmitter 来做吗?
  • 是的,你可以在接收组件上使用@Output() scrollPos:EventEmitter@Input() scrollPos,如果它们是父子组件,可以在模板中绑定。
  • 为此打开了单独的问题:stackoverflow.com/questions/36471927/…

标签: angular typescript events scroll


【解决方案1】:

我认为最简单的方法是每个感兴趣的组件都监听滚动事件。

  @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

Plunker using @HostListener()

提示:

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

使指令通用,无需将其添加到每个组件 directive: [...] 列表中。

【讨论】:

【解决方案2】:

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

@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()
  }
}

【讨论】:

  • 对于那些在不是窗口的 DOM 元素中寻找滚动事件的人来说,这是正确的答案。就我而言,我正在跟踪嵌套在 DOM 树下的
    的滚动。 event.srcElement.scrollTop 像魅力一样工作
【解决方案3】:

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

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

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

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

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

【讨论】:

    【解决方案4】:

    我有一个类似的问题,当用户滚动页面时我需要滚动一个 div,并用下面的代码解决了我的问题。 在要捕获滚动的组件处:

    import { HostListener } from '@angular/core';
    
    @ViewChild('curtain') divCurtain: ElementRef;
    
    export class ComponentX {
        @HostListener('window:scroll', ['$event']) onScrollEvent($event) {
            console.log(window.pageYOffset);
            this.divCurtain.nativeElement.style.top = window.pageYOffset.toString().concat('px');
        }
    
        ngOnInit(): void { }
    }
    

    仅此,我没有创建任何指令或其他代码。 每次用户滚动页面时都会执行此 HostListener,然后我将 window.pageYOffset 发送到我的 div。

    希望对你有帮助。

    【讨论】:

      猜你喜欢
      • 2020-11-26
      • 2016-02-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多