【问题标题】:Angular2 / TypeScript - Variable not changedAngular2 / TypeScript - 变量未更改
【发布时间】:2016-04-09 17:26:59
【问题描述】:

看起来我的变量的isInfinitiveScrollLoaderEnabled 值在到达页面底部时没有改变。如果我把ngOnInit方法放在开头,就改成功了。

可能出了什么问题?

export class SomeClass {
  private isInfinitiveScrollLoaderEnabled: boolean;

  constructor() {
    this.isInfinitiveScrollLoaderEnabled = false;
  }

  ngOnInit() {
    window.onscroll = (event) => {
      if ((window.innerHeight + window.scrollY) >= document.body.scrollHeight) {
        console.log('Bottom of page');
        this.isInfinitiveScrollLoaderEnabled = true;
      }
    };
  }
}

【问题讨论】:

    标签: typescript angular


    【解决方案1】:

    Angular 提供了一种简单的方法来监听 windowdocument 上的事件:

    @Component({
      selector: 'some-class',
      // alternative to @HostListener below
      // host: {'(window:scroll)':'onScroll($event')},
      ...
    })
    export class SomeClass {
      private isInfinitiveScrollLoaderEnabled: boolean;
    
      constructor() {
        this.isInfinitiveScrollLoaderEnabled = false;
      }
    
      @HostListener('window:scroll', ['$event'])
      onScroll(event) {
        if ((window.innerHeight + window.scrollY) >= document.body.scrollHeight) {
          console.log('Bottom of page');
          this.isInfinitiveScrollLoaderEnabled = true;
        }
      }
    }
    

    有关命令式的方法,请参阅Programmatically (un)register to event with Angular 2

    【讨论】:

      【解决方案2】:

      当事件触发时,您需要利用 NgZone 类在 Angular2 的上下文中执行 onscroll 回调:

      export class SomeClass {
        private isInfinitiveScrollLoaderEnabled: boolean;
      
        constructor(private ngZone: NgZone) {
          this.isInfinitiveScrollLoaderEnabled = false;
        }
      
        ngOnInit() {
          window.onscroll = (event) => {
            if ((window.innerHeight + window.scrollY) >= document.body.scrollHeight) {
              console.log('Bottom of page');
              this.ngZone.run(() => {
                this.isInfinitiveScrollLoaderEnabled = true;
              });
            }
          };
        }
      }
      

      看到这个 plunkr:https://plnkr.co/edit/PI5wbMnWEY56EiB4wGEH?p=preview

      这是因为 window 对象在 Angular2 之外实例化...

      【讨论】:

        【解决方案3】:

        Günter Zöchbauer 的回答是完美的(赞成)。我想解释一下:

        Angular2 内部使用的 Zone 库对许多 API 进行了修补,包括事件侦听器 API。但这不包括窗口/元素on<EVENT> 属性,可能是因为它们被认为是旧的并且不鼓励使用。

        但如果您使用addEventListener API,这应该可以正常工作。

        例子:

        export class SomeClass {
          private isInfinitiveScrollLoaderEnabled: boolean;
        
          constructor(private ngZone: NgZone) {
            this.isInfinitiveScrollLoaderEnabled = false;
          }
        
          ngOnInit() {
            window.addEventListener('scroll', (event) => {
              if ((window.innerHeight + window.scrollY) >= document.body.scrollHeight) {
                console.log('Bottom of page');
                this.isInfinitiveScrollLoaderEnabled = true;
              }
            });
          }
        }
        

        当然,如果您可以抽象出 DOM 以用于服务器渲染或 NativeScript / ReactNative 等移动框架,您可以选择其他有效选项

        import {DOM} from 'angular2/platform/common_dom.dart';
        
        DOM
            .getGlobalEventTarget('window')
            .addEventListener('message', function, false);
        

        或者

        @HostListener('window:scroll', ['$event'])`
        

        这对我来说看起来最具声明性。

        正如 Günter Zöchbauer 提到的那样。

        如果您不关心这些渲染注意事项,它们在您的代码中可能看起来很陌生。无论哪种方式都是您的电话,应该没问题。

        无论你选择什么,我都会远离this.ngZone.run() 选项,因为它会带来$scope.$apply() 时代的糟糕回忆,尽管它确实没有那么糟糕。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2023-03-17
          • 1970-01-01
          • 2016-06-03
          • 2017-04-19
          • 2016-12-11
          • 1970-01-01
          • 1970-01-01
          • 2017-06-08
          相关资源
          最近更新 更多