首页 > 解决方案 > 了解 Angular 中的作用域

问题描述

我对角度很陌生,所以我希望这个问题不是太基本。我正在尝试以角度运行一个函数,但我的变量范围似乎存在问题。这是它的样子:

export class Skulder14q1Component {

  button1 = document.getElementById('button1');
  button2 = document.getElementById('button2');
  button3 = document.getElementById('button3');
  button4 = document.getElementById('button4');
  showallbutton = document.getElementById('showallbutton');

  onShowAllOptions() {
    this.button1.classList.toggle('hide');
    this.button2.classList.toggle('hide');
    this.button3.classList.toggle('hide');
    this.button4.classList.toggle('hide');
    this.showallbutton.classList.add('hide');
  }

现在该功能通过按下按钮运行,但是当按下按钮时,控制台日志返回:

> Skulder14q1Component.html:12 ERROR TypeError: Cannot read property 'classList' of null
    at Skulder14q1Component.onShowAllOptions (skulder14q1.component.ts:28)
    at Object.eval [as handleEvent] (Skulder14q1Component.html:15)
    at handleEvent (core.js:10251)
    at callWithDebugContext (core.js:11344)
    at Object.debugHandleEvent [as handleEvent] (core.js:11047)
    at dispatchEvent (core.js:7710)
    at core.js:8154
    at HTMLButtonElement.<anonymous> (platform-browser.js:988)
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:421)
    at Object.onInvokeTask (core.js:3811)

改为此代码有效:

onShowAllOptions() {
  const button1 = document.getElementById('button1');
  const button2 = document.getElementById('button2');
  const button3 = document.getElementById('button3');
  const button4 = document.getElementById('button4');
  const showallbutton = document.getElementById('showallbutton');
  button1.classList.toggle('hide');
  button2.classList.toggle('hide');
  button3.classList.toggle('hide');
  button4.classList.toggle('hide');
  showallbutton.classList.add('hide');
}

我觉得我缺少一些基本的东西,我希望你能帮助我。谢谢!

标签: angular

解决方案


首先,我建议不要通过标准的浏览器方法来管理 DOM,比如document.getElementById等。推荐使用 Angular 抽象,你可以在这里阅读更多内容。

顺便说一句,我们可以找到原因

初始化时Skulder14q1Component,它的 DOM(HTML 元素/模板)尚未创建。因此,当您尝试查找按钮时,它们还不存在,因此getElementById返回null

Angular 中的组件经历了一个生命周期,你可以通过向你的类中添加某些方法来挂钩这个生命周期。您可以在有关生命周期钩子的文档中阅读有关这些内容的更多信息。

在你的情况下,你需要AfterViewInit钩子。为了实现它,我们需要做两件事:

  1. 实现接口AfterViewInit

    class Skulder14q1Component implements AfterViewInit {
    ...
    }
    
  2. 添加方法

    class Skulder14q1Component implements AfterViewInit {
        button1: HTMLElement;
        button2: HTMLElement;
        button3: HTMLElement;
        button4: HTMLElement;
        showAllButton: HTMLElement;
    
        ngAfterViewInit() {
            this.button1 = document.getElementById('button1');
            this.button2 = document.getElementById('button2');
            this.button3 = document.getElementById('button3');
            this.button4 = document.getElementById('button4');
            this.showallbutton = document.getElementById('showallbutton');
        }
    
        // when this is called later, the buttons will have been set up
        onShowAllOptions() {
            this.button1.classList.toggle('hide');
            this.button2.classList.toggle('hide');
            this.button3.classList.toggle('hide');
            this.button4.classList.toggle('hide');
            this.showallbutton.classList.add('hide');
        }
    }
    

该方法中的代码将在 Angular 为您准备好模板后运行。


编辑:根据我的经验,ViewChild不经常使用,因为您希望模板中的元素(特别是如果它们是其他组件)对自己的行为负责,而不是控制全能类的所有内容。

这是我为您的用例制作的StackBlitz 。


推荐阅读