Почему @ViewChild не может работать вне AfterViewInit?

поэтому я пытаюсь сделать некоторые события основанными на прокрутке моего приложения Angular.

У меня проблема, так как я пытаюсь получить доступ к элементу в своем HTML с помощью @ViewChild.

Я могу получить доступ к элементу внутри ngAfterViewInit(), но не могу получить к нему доступ снаружи. Всегда показывает undefined.

Вот мой класс компонентов:

export class NavBarComponent implements OnInit {

  @ViewChild('navBar')
  navBar:ElementRef;

  constructor(private renderer: Renderer2) {
  }

  ngAfterViewInit(){
    window.addEventListener('scroll', this.onScroll, true);
    console.log(this.navBar.nativeElement);
  }

  ngOnInit(): void {

  }

  onScroll(){
    console.log("I am scrolling right now.")
    console.log(this.navBar.nativeElement)
  }

  onResize(){

  }

  onTabClick(){

  }
}

Когда я вхожу в консоль внутри ngAfterViewInit(), я получаю элемент HTML, но когда я вхожу в консоль внутри onScroll(), он не определен.

Почему мой элемент исчезает и становится неопределенным после просмотра? Я не использую ngIf или что-то еще, что удаляет элемент.

Вот HTML-код компонента.

  <section class="et-hero-tabs" >
    <h1>STICKY SLIDER NAV</h1>
    <h3>Sliding content with sticky tab nav</h3>
    <div class="et-hero-tabs-container" #navBar>
      <a class="et-hero-tab" href="">ES6</a>
      <a class="et-hero-tab" href="">Flexbox</a>
      <a class="et-hero-tab" href="">React</a>
      <a class="et-hero-tab" href="">Angular</a>
      <a class="et-hero-tab" href="">Other</a>
      <span class="et-hero-tab-slider"></span>
    </div>
  </section>

Вот ошибка консоли: введите здесь описание изображения


person Allamo Olsson    schedule 28.05.2020    source источник
comment
Проблема в том, как вы называете this.onScroll. Чтобы сохранить this, вы можете: (1) определить обратный вызов как стрелочную функцию: onScroll = () => { ... } или (2) заключить вызов в стрелочную функцию: window.addEventListener('scroll', () => { this.onScroll(); }, true);.   -  person ConnorsFan    schedule 28.05.2020
comment
вы также можете использовать rxjs fromEvent:learnrxjs.io/learn-rxjs/operators/creation /от события. fromEvent(window,'scroll').subscribe(res=>{...}) это позволит вам отказаться от подписки, отложить или ...   -  person Eliseo    schedule 28.05.2020


Ответы (1)


Вы можете связать значение ключевого слова this в функции обратного вызова, используя bind(). Попробуйте следующее

ngAfterViewInit(){
  window.addEventListener('scroll', this.onScroll.bind(this), true);
  console.log(this.navBar.nativeElement);
}

Без привязки область действия ключевого слова this в обратном вызове onScroll() не указывает на область действия класса.

person Michael D    schedule 28.05.2020
comment
Я понимаю, что происходит сейчас с этим ответом. Но есть ли причина, по которой переменная становится неопределенной? В моем случае navBar? Может быть, я спрашиваю: если определено один раз, почему оно не всегда определено? - person Allamo Olsson; 28.05.2020
comment
Когда вы передаете обратный вызов напрямую, ключевое слово this будет указывать на область действия функции. И в функции нет никакой переменной navBar. Используя bind(this), вы можете сказать обратному вызову использовать this из области действия функции ngAfterViewInit(), которая будет указывать на класс. - person Michael D; 28.05.2020
comment
О, хорошо. Итак, я в основном даю контекст класса функции. Но как я могу регистрировать другие переменные класса? Извините за мои глупые вопросы. Я понимаю, что вы имели в виду, я просто пытаюсь понять, почему единственный возможный способ доступа к этой переменной находится в области действия AfterViewInit. - person Allamo Olsson; 28.05.2020
comment
Вы не сможете получить доступ к каким-либо переменным-членам без ссылки на this. Если переменные не определены внутри функции. - person Michael D; 28.05.2020