Angular12 - 使用 @HostBinding 或 @HostListener 而不是 `host` 元数据属性
Posted
技术标签:
【中文标题】Angular12 - 使用 @HostBinding 或 @HostListener 而不是 `host` 元数据属性【英文标题】:Angular12 - Use @HostBinding or @HostListener rather than the `host` metadata property 【发布时间】:2021-10-03 02:11:59 【问题描述】:我正在使用带有 ESLint 的 Angular 12,而 ESLint 打印出以下错误:
70:3 错误使用 @HostBinding 或 @HostListener 而不是
host
元数据属性 (https://angular.io/styleguide#style-06-03) @angular-eslint/no-host-metadata-property
类似的话题还有很多,比如this one,但是我的宿主比较复杂。
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();
【问题讨论】:
【参考方案1】:您的主机绑定应该返回布尔值(根据组件的状态计算),并且当前您正在为其分配一个字符串值。请记住,它是 typescript 文件的一部分,在您的组件中,因此您可以访问所有属性。
所以,这样的事情应该可以工作:
@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())
);
请注意,我不会在类的构建过程中赋值一次。相反,我使用的是带有 getter 的属性。这意味着主机绑定将在每个更改检测周期更新。
【讨论】:
谢谢!就像i.imgur.com/Cx73RiK.png? 嗯,不知何故效果不起作用。我需要在某处指定变量吗?这是用法:<li app-menu-item *ngFor="let item of model; let i = index" [item]="item" [index]="i" [root]="true"></li>
.
对不起,我犯了一个复制粘贴错误。删除@HostBinding 中的括号,即@HostBinding('class.active-menuitem')
。我制作了一个简化的 stackblitz 示例 here - 这取决于传递的 name
值的长度。以上是关于Angular12 - 使用 @HostBinding 或 @HostListener 而不是 `host` 元数据属性的主要内容,如果未能解决你的问题,请参考以下文章
Angular12 - 使用 @HostBinding 或 @HostListener 而不是 `host` 元数据属性
Angular 12 的 Storybook 插件 StoryShots