有没有一种更 Angular 的方式来获取指令中给定的 elementRef 的子元素

问题描述 投票:0回答:1

我有一个指令负责我页面上的汉堡菜单,它看起来像这样:

@Directive({
  selector: '[sideNavToggler]'
})
export class SidenavtogglerDirective implements AfterViewInit {

  private sideNav: HTMLElement
  private burgerButton: HTMLElement

  constructor(private el: ElementRef, private renderer: Renderer2) { }

  ngAfterViewInit(): void {
    this.sideNav = this.el.nativeElement.querySelector('.menu__box')
    this.burgerButton = this.el.nativeElement.querySelector('.menu__btn')
  }

  

  @HostListener('click') toggleOpenClass(){
    if (this.sideNav && this.burgerButton) {
      
      this.sideNav.classList.contains('open')
      ? this.renderer.removeClass(this.sideNav,'open')
      : this.renderer.addClass(this.sideNav, 'open')

      this.burgerButton.classList.contains('active')
      ? this.renderer.removeClass(this.burgerButton,'active')
      : this.renderer.addClass(this.burgerButton,'active')
      
    }
  }
}

它工作得很好,但我不认为使用 .querySelector 是 Angular 应用程序中的最佳实践。我在互联网上没有找到任何与我的情况类似的有用信息。我怎样才能使这段代码变得更好或者它已经足够了?我正在使用 Angular 16

angular typescript dom-events
1个回答
0
投票

使用指令时需要使用

ContentChild
,请在下面找到一个工作示例供您参考。

CSS

.active {
  background-color: red;
}
.open {
  background-color: yellow;
}
.hamburger-menu {
  border: 1px solid black;
}

main.ts

import { Component } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import 'zone.js';
import { SidenavtogglerDirective } from './side-nav-toggler.directive';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [SidenavtogglerDirective],
  template: `
    <div class="hamburger-menu" sideNavToggler>
      click inside to change color<br/>
    <label class="menu__btn active" for="menu__toggle" #menuButton>
      <span>label</span>
    </label>

    <ul class="menu__box open" #menuBox>
      <li><a class="menu__item" href="#">hello</a></li>
    </ul>
  </div>
  `,
})
export class App {
  name = 'Angular';
}

bootstrapApplication(App);

指令

import {
  Directive,
  HostListener,
  Renderer2,
  AfterViewInit,
  ViewChild,
  ElementRef,
  ContentChild,
} from '@angular/core';

@Directive({
  selector: '[sideNavToggler]',
  standalone: true,
})
export class SidenavtogglerDirective implements AfterViewInit {
  @ContentChild('menuBox') menuBox!: ElementRef<HTMLElement>;
  @ContentChild('menuButton') menuButton!: ElementRef<HTMLElement>;

  constructor(private renderer: Renderer2) {}

  ngAfterViewInit(): void {}

  @HostListener('click', ['$event.target'])
  toggleOpenClass() {
    if (this.menuBox && this.menuButton) {
      console.log(this.menuBox.nativeElement.classList.contains('open'));
      this.menuBox.nativeElement.classList.contains('open')
        ? this.renderer.removeClass(this.menuBox.nativeElement, 'open')
        : this.renderer.addClass(this.menuBox.nativeElement, 'open');

      this.menuButton.nativeElement.classList.contains('active')
        ? this.renderer.removeClass(this.menuButton.nativeElement, 'active')
        : this.renderer.addClass(this.menuButton.nativeElement, 'active');
    }
  }
}

堆栈闪电战

© www.soinside.com 2019 - 2024. All rights reserved.