我遇到了与Angular生命周期挂钩相关的问题,因为触发了OnDestroy事件,并且我的组件似乎仍然具有其侦听器。
我有一个项目列表和每个项目的饼图,将它们悬停时会触发一个弹出窗口。该弹出窗口是由Angular Material材质制成的自定义组件,但它遵循类似组件的行为(例如mat-menu)。它具有一个onOpen侦听器,可在打开弹出窗口时触发。
这里的问题是,在应该销毁组件及其父对象之后,悬停仍然有效,这在每次重新加载项目列表时都会发生。
这是我的实现的简化版本:
// Table component
import { Component, OnInit, OnDestroy, ChangeDetectorRef, ChangeDetectionStrategy } from '@angular/core';
import { select, Store } from '@ngrx/store';
import { Project } from '@models';
import { projectsSelectors } from '@store/track';
import { Subscription } from 'rxjs';
import { Observable } from 'rxjs/Observable';
@Component({
selector: 'app-projects-table',
templateUrl: './projects-table.component.html',
styleUrls: ['./projects-table.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ProjectsTableComponent implements OnInit, OnDestroy {
projects$: Observable<Array<Project>>;
projects: Array<Project>;
subs = new Subscription();
constructor(
private store: Store<any>,
private cd: ChangeDetectorRef,
) {}
ngOnInit() {
this.projects$ = this.store.select(projectsSelectors.all);
this.subs = this.projects$.subscribe((projects) => {
this.projects = projects;
this.cd.detectChanges();
});
}
trackByFn(index, item) {
return item.id;
}
ngOnDestroy() {
this.subs.unsubscribe();
}
}
// Pie component
import {
ChangeDetectionStrategy,
Component,
Input,
ViewChild,
OnDestroy,
OnInit,
} from '@angular/core';
import { PopoverPanel } from '@ng-components';
import {
Project,
} from '@models';
import * as moment from 'moment';
@Component({
selector: 'app-pie',
templateUrl: './app-pie.component.html',
styleUrls: ['./app-pie.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class PieComponent implements OnInit, OnDestroy {
@Input() project: Project;
@ViewChild('piePopover')
budgetCompletionPopover: PopoverPanel;
ngOnInit() {
console.log('Init budget progress pie', this.budgetCompletionPopover);
}
ngOnDestroy() {
console.log('Destroy pie');
}
}
// Pie popover component
import { Component, Output, EventEmitter, Input, OnDestroy, OnInit } from '@angular/core';
import { PopoverPanelComponent } from '@ng-components';
import { Project } from '@/models';
@Component({
selector: 'app-pie-popover',
templateUrl: './pie-popover.component.html',
})
export class PiePopoverComponent extends PopoverPanelComponent implements OnInit, OnDestroy {
@Input() project: IProject;
@Output() close = new EventEmitter<void>();
@Output() open = new EventEmitter<void>();
constructor() {
super();
this.alignment = 'top';
this.position = 'before';
this.targetOffsetX = -84;
this.triggerEvent = 'hover';
this.overlapTrigger = true;
}
ngOnInit() {
console.log('Init pie popover');
}
onOpen() {
console.log('Opened pie popover', this.project.id);
}
ngOnDestroy() {
console.log('Destroy and close pie popover', this.project.id);
this.close.emit();
}
}
<!-- Pie Table Component -->
<table class="table">
<app-projects-table-header class="table-head">
<app-projects-table-filter></app-projects-table-filter>
</app-projects-table-header>
<tbody class="table-body">
<tr *ngFor="let project of projects; trackBy: trackByFn">
<app-pie [project]="project"></app-pie>
</tr>
</tbody>
</table>
<!-- Pie Component -->
<div class="container" [popoverTriggerFor]="piePopover">
<ng-container>
<!-- Project information displayed here -->
</ng-container>
<app-pie-chart
class="graph-pie"
[size]="55"
[strokeWidth]="4"
[progress]="completionRatio"
[displayValue]="100 * completionRatio"
>
</app-pie-chart>
</div>
<app-pie-popover
#piePopover
[project]="project"
></app-pie-popover>
当项目重新加载时,我一直将鼠标悬停在饼上时,控制台输出:
悬停饼图
触发重新加载并回到悬停饼图
我希望在应该避免显示问题的情况下完全破坏popover组件。 欢迎您提供任何线索,谢谢!