Angular12 - 使用@HostBinding 或@HostListener 而不是`host` 元数据属性

Angular12 - Use @HostBinding or @HostListener rather than the `host` metadata property

我正在使用 Angular 12 和 ESLint,ESLint 打印出以下错误:

70:3 error Use @HostBinding or @HostListener rather than the host metadata property (https://angular.io/styleguide#style-06-03) @angular-eslint/no-host-metadata-property

有很多类似的话题,比如,但我的主机比较复杂。

  host: {
    '[class.active-menuitem]':
      '(selectedKey && app.isHorizontal()) || (active && !app.isHorizontal()) ' +
      '|| (active && !root && app.isHorizontal())',
    '[class.active-rootmenuitem]': 'active && root && app.isHorizontal()'
  },

我应该怎么做?类似于:

@HostBinding('[class.active-menuitem]') menuItem = '(selectedKey && app.isHorizontal()) || (active && !app.isHorizontal()) ' + '|| (active && !root && app.isHorizontal())'; 

?

完整片段:

import { Component, Input, OnInit, ChangeDetectorRef, OnDestroy } from '@angular/core';
import { Router, NavigationEnd } from '@angular/router';
import { trigger, state, style, transition, animate } from '@angular/animations';
import { Subscription } from 'rxjs';
import { filter } from 'rxjs/operators';
import { LayoutComponent } from '../layout.component';
import { MenuService } from '@core/services';

@Component({
  selector: '[app-menu-item]',
  template: `
    <ng-container>
      <a
        [attr.href]="item.url"
        (click)="itemClick($event)"
        *ngIf="!item.routerLink || item.items"
        pRipple
        [ngClass]="item.class"
        (mouseenter)="onMouseEnter()"
        (keydown.enter)="itemClick($event)"
        [attr.target]="item.target"
        [attr.tabindex]="0"
      >
        <i [ngClass]="item.icon" class="layout-menuitem-icon"></i>
        <span class="layout-menuitem-text">{{ item.label }}</span>
        <i class="pi pi-fw pi-angle-down layout-submenu-toggler" *ngIf="item.items"></i>
      </a>
      <a
        (click)="itemClick($event)"
        (mouseenter)="onMouseEnter()"
        *ngIf="item.routerLink && !item.items"
        pRipple
        [ngClass]="item.class"
        [routerLink]="item.routerLink"
        routerLinkActive="active-menuitem-routerlink"
        [routerLinkActiveOptions]="{ exact: true }"
        [attr.target]="item.target"
        [attr.tabindex]="0"
      >
        <i [ngClass]="item.icon" class="layout-menuitem-icon"></i>
        <span class="layout-menuitem-text">{{ item.label }}</span>
        <i class="pi pi-fw pi-angle-down layout-submenu-toggler" *ngIf="item.items"></i>
      </a>
      <ul
        *ngIf="item.items && (active || animating || selectedKey)"
        (@children.done)="onAnimationDone()"
        [ngStyle]="{ padding: active && root ? '' : '0' }"
        [@children]="
          app.isHorizontal() && root && !app.isMobile()
            ? active
              ? 'visible'
              : 'hidden'
            : active
            ? 'visibleAnimated'
            : 'hiddenAnimated'
        "
      >
        <ng-template ngFor let-child let-i="index" [ngForOf]="item.items">
          <li
            app-menu-item
            [item]="child"
            [index]="i"
            [parentKey]="key"
            [class]="child.badgeClass"
          ></li>
        </ng-template>
      </ul>
    </ng-container>
  `,
  host: {
    '[class.active-menuitem]':
      '(selectedKey && app.isHorizontal()) || (active && !app.isHorizontal()) ' +
      '|| (active && !root && app.isHorizontal())',
    '[class.active-rootmenuitem]': 'active && root && app.isHorizontal()'
  },
  animations: [
    trigger('children', [
      state(
        'void',
        style({
          height: '0px'
        })
      ),
      state(
        'hiddenAnimated',
        style({
          height: '0px'
        })
      ),
      state(
        'visibleAnimated',
        style({
          height: '*'
        })
      ),
      state(
        'visible',
        style({
          height: '*',
          'z-index': 999
        })
      ),
      state(
        'hidden',
        style({
          height: '0px',
          'z-index': '*'
        })
      ),
      transition(
        'visibleAnimated => hiddenAnimated',
        animate('400ms cubic-bezier(0.86, 0, 0.07, 1)')
      ),
      transition(
        'hiddenAnimated => visibleAnimated',
        animate('400ms cubic-bezier(0.86, 0, 0.07, 1)')
      ),
      transition(
        'void => visibleAnimated, visibleAnimated => void',
        animate('400ms cubic-bezier(0.86, 0, 0.07, 1)')
      )
    ])
  ]
})
export class MenuItemComponent implements OnInit, OnDestroy {
  @Input() item: any;
  @Input() index: number;
  @Input() root: boolean;
  @Input() parentKey: string;

  animating: boolean;
  active = false;
  menuSourceSubscription: Subscription;
  menuResetSubscription: Subscription;

  key: string;

  selectedKey: boolean;

  constructor(
    public app: LayoutComponent,
    public router: Router,
    private cd: ChangeDetectorRef,
    private menuService: MenuService
  ) {
    this.menuSourceSubscription = this.menuService.menuSource$.subscribe((key) => {
      // deactivate current active menu
      if (this.active && this.key !== key && key.indexOf(this.key) !== 0) {
        this.active = false;
      }
    });

    this.menuResetSubscription = this.menuService.resetSource$.subscribe(() => {
      this.active = false;
    });

    this.router.events
      .pipe(filter((event) => event instanceof NavigationEnd))
      .subscribe((params) => {
        if (this.app.isHorizontal() && this.item.routerLink) {
          this.active = false;
          this.selectedKey = this.router.isActive(
            this.item.routerLink[0],
            this.item.items ? false : true
          );
        } else {
          if (this.item.routerLink) {
            this.updateActiveStateFromRoute();
          } else {
            this.active = false;
          }
        }
      });
  }

  ngOnInit() {
    if (!this.app.isHorizontal() && this.item.routerLink) {
      this.updateActiveStateFromRoute();
    }

    if (this.app.isHorizontal() && this.item.routerLink) {
      this.active = false;
      this.selectedKey = this.router.isActive(
        this.item.routerLink[0],
        this.item.items ? false : true
      );
    }

    this.key = this.parentKey ? this.parentKey + '-' + this.index : String(this.index);
  }

  updateActiveStateFromRoute() {
    this.active = this.router.isActive(this.item.routerLink[0], this.item.items ? false : true);
  }

  itemClick(event: Event) {
    // avoid processing disabled items
    if (this.item.disabled) {
      event.preventDefault();
      return;
    }

    // navigate with hover in horizontal mode
    if (this.root) {
      this.app.menuHoverActive = !this.app.menuHoverActive;
    }

    // notify other items
    this.menuService.onMenuStateChange(this.key);

    // execute command
    if (this.item.command) {
      this.item.command({ originalEvent: event, item: this.item });
    }

    // toggle active state
    if (this.item.items) {
      this.active = !this.active;
      this.animating = true;
    } else {
      // activate item
      this.active = true;

      // reset horizontal menu
      if (this.app.isHorizontal()) {
        this.menuService.reset();
      }

      this.app.overlayMenuActive = false;
      this.app.overlayMenuMobileActive = false;
      this.app.menuHoverActive = !this.app.menuHoverActive;
    }
  }

  onMouseEnter() {
    // activate item on hover
    if (this.root && this.app.menuHoverActive && this.app.isHorizontal() && this.app.isDesktop()) {
      this.menuService.onMenuStateChange(this.key);
      this.active = true;
    }
  }

  onAnimationDone() {
    this.animating = false;
  }

  ngOnDestroy() {
    if (this.menuSourceSubscription) {
      this.menuSourceSubscription.unsubscribe();
    }

    if (this.menuResetSubscription) {
      this.menuResetSubscription.unsubscribe();
    }
  }
}

您的主机绑定应该 return 布尔值(根据组件的状态计算),目前您正在为其分配一个字符串值。请记住,它是打字稿文件的一部分,在您的组件中,因此您可以访问所有属性。

所以,像这样的东西应该可以工作:

@HostBinding('class.active-menuitem') get activeMenuItem(): boolean {
  return (
    (this.selectedKey && this.app.isHorizontal()) ||
    (this.active && !this.app.isHorizontal()) ||
    (this.active && !this.root && this.app.isHorizontal())
  );
}

请注意,我在 class 的构造过程中没有一次赋值。相反,我使用 属性 和 getter。这意味着主机绑定将在每个更改检测周期更新。