为啥@ViewChild 不能在 AfterViewInit 之外运行? [复制]

Posted

技术标签:

【中文标题】为啥@ViewChild 不能在 AfterViewInit 之外运行? [复制]【英文标题】:Why cant @ViewChild run outside AfterViewInit? [duplicate]为什么@ViewChild 不能在 AfterViewInit 之外运行? [复制] 【发布时间】:2020-09-16 01:40:29 【问题描述】:

所以我试图根据我的 Angular 应用程序的滚动来做一些事件。

我遇到了一个问题,因为我试图在 @ViewChild 的帮助下访问我的 html 中的元素。

我可以访问ngAfterViewInit() 中的元素,但我无法访问它之外的元素。它总是显示未定义。

这是我的组件类:

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() 中进行控制台登录时,它是未定义的。

为什么我的元素在 viewinit 后消失并且未定义?我没有使用任何 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>

这是控制台错误:

【问题讨论】:

问题在于你调用this.onScroll的方式。要保留this,您可以:(1) 将回调定义为箭头函数:onScroll = () =&gt; ... ,或 (2) 将调用包装在箭头函数中:window.addEventListener('scroll', () =&gt; this.onScroll(); , true); 你也可以使用 rxjs "fromEvent":learnrxjs.io/learn-rxjs/operators/creation/fromevent。 fromEvent(window,'scroll').subscribe(res=&gt;...) 这允许您取消订阅、延迟或... 【参考方案1】:

您可以使用bind() 方法在回调函数中绑定this 关键字的含义。试试下面的

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

如果没有绑定,onScroll() 回调中this 关键字的范围不会指向类的范围。

【讨论】:

我明白这个答案现在会发生什么。但是变量未定义是否有原因?在我的情况下“导航栏”?也许我要问的是:如果定义一次,为什么不总是定义? 当你直接传递回调时,this 关键字将指向函数的作用域。并且在函数中没有任何 navBar 变量。使用bind(this),您可以告诉回调在ngAfterViewInit() 函数的范围内使用this,该函数将指向该类。 哦,好吧。所以我基本上是给函数提供类上下文。但是我怎么能记录其他类变量呢?对不起我的愚蠢问题。我明白你的意思我只是想了解为什么访问该变量的唯一可能方法是在 AfterViewInit 的范围内。 如果不引用this,您将无法访问任何成员变量。除非变量是在函数内部定义的。

以上是关于为啥@ViewChild 不能在 AfterViewInit 之外运行? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

如果我们不能从父组件更改属性或操作它们,@ViewChild 有啥用?

Angular 在项目中学习@ViewChild和ElementRef的使用

Angular Viewchild undefined

Angular 2+:获取@ViewChild() 的子元素

错误 TS2554:预期 2 个参数,但使用 @ViewChild 得到 1 个

在 html 中动态命名 div 并使用 @ViewChild('xyz') div: ElementRef;在角度