平滑滚动抛出意外的未定义 属性 错误

Smooth scroll throws unexpected undefined property error

我一直在尝试实现某种平滑滚动。我关注了 this codepen to create such scroll: https://codepen.io/osublake/pen/QqPqbN

我试图翻译成 TypeScript/Angular,但它仍然以某种方式抛出以下错误 - 不是在 ngAfterViewInit 内部调用 updateScroller() 时,而是当我第一次尝试滚动 - 指向 const resized = this.scroller.resizeRequest > 0:

core.js:9110 ERROR TypeError: Cannot read property 'scroller' of undefined
    at updateScroller (app.component.ts:50)
    at ZoneDelegate.invokeTask (zone-evergreen.js:391)
    at Object.onInvokeTask (core.js:34182)
    at ZoneDelegate.invokeTask (zone-evergreen.js:390)
    at Zone.runTask (zone-evergreen.js:168)
    at invokeTask (zone-evergreen.js:465)
    at ZoneTask.invoke (zone-evergreen.js:454)
    at timer (zone-evergreen.js:2650)
export class AppComponent implements OnInit, AfterViewInit {

  scroller = {
    target: document.querySelector('.scrollable-container'),
    ease: 0.05,
    endY: 0,
    y: 0,
    resizeRequest: 1,
    scrollRequest: 0,
  };

  requestId = null;

  constructor(@Inject(PLATFORM_ID) private platformId) {
  }

  ngOnInit() {
    if (isPlatformBrowser(this.platformId)) {
      console.log('Hi, this is NØREBRO!');
    }
  }

  ngAfterViewInit(): void {
    setTimeout(() => {
      this.scroller.target = document.querySelector('.scrollable-container');

      TweenLite.set(this.scroller.target, {
        rotation: 0.01,
        force3D: true
      });

      this.updateScroller();
    });
    window.focus();
  }

  updateScroller() {
    const html = document.documentElement;
    const body = document.body;

    const resized = this.scroller.resizeRequest > 0;

    if (resized) {
      const height = this.scroller.target.clientHeight;
      body.style.height = height + 'px';
      this.scroller.resizeRequest = 0;
    }

    const scrollY = window.pageYOffset || html.scrollTop || body.scrollTop || 0;

    this.scroller.endY = scrollY;
    this.scroller.y += (scrollY - this.scroller.y) * this.scroller.ease;

    if (Math.abs(scrollY - this.scroller.y) < 0.05 || resized) {
      this.scroller.y = scrollY;
      this.scroller.scrollRequest = 0;
    }

    TweenLite.set(this.scroller.target, {
      y: -this.scroller.y
    });

    this.requestId = this.scroller.scrollRequest > 0 ? requestAnimationFrame(this.updateScroller) : null;
  }

  @HostListener('window:scroll', [])
  scroll() {
    this.scroller.scrollRequest++;
    console.log(this.requestId);
    if (!this.requestId) {
      console.log('uff');
      this.requestId = requestAnimationFrame(this.updateScroller);
    }
  }

}

似乎 thisundefined 重复的方法调用。在无法调试您的应用程序的情况下,我假设您需要将 this 作为范围添加到您的 this.updateScroller 方法中。

函数的作用域 (this) 始终由执行上下文决定,使用 requestAnimationFrame 函数在 class 实例(组件)的上下文之外调用。有几篇关于函数作用域的有趣文章,例如参见 this

应该有两种方法可以解决您的问题:

a) 将所有 requestAnimationFrame(this.updateScroller) 调用替换为

requestAnimationFrame(this.updateScroller.bind(this))

b) 将所有 requestAnimationFrame(this.updateScroller) 调用替换为

requestAnimationFrame(() => {
  this.updateScroller()
})