简介
我今天偶然发现了这个,我真的可以看到很多应用程序都需要这个实现。现在我不能保证这是 100% 最好的技术,但是我已经竭尽全力使这种方法尽可能有角度的启发。
我提出的方法分为两个阶段。第 1 阶段和第 2 阶段将总共添加 years * months + years * months * days,因此在 1 年内您将拥有 12 + 365 事件。
舞台范围
第 1 阶段: 将事件从点击月份开始到点击的实际日期,而不需要当天的事件。
第 2 阶段:将所选日期传播回月份。
在深入研究之前,该应用程序由 3 个组件组成,这些组件按以下顺序嵌套:app => month => day
这是所需的所有 html。 app.component 托管多个月,month.component 托管多个天,而 day.component 什么都不做,只是将它的日期显示为文本。
app.component.html
<app-month *ngFor="let month of months" [data-month]="month"></app-month>
month.component.html
<app-day *ngFor="let day of days" [data-day]="day">{{day}}</app-day>
day.component.html
<ng-content></ng-content>
这是相当标准的东西。
第一阶段
让我们看一下我们要从中委派事件的month.component.ts。
// obtain a reference to the month(this) element
constructor(private element: ElementRef) { }
// when this component is clicked...
@HostListener('click', ['$event'])
public onMonthClick(event) {
// check to see whether the target element was a child or if it was in-fact this element
if (event.target != this.element.nativeElement) {
// if it was a child, then delegate our event to it.
// this is a little bit of javascript trickery where we are going to dispatch a custom event named 'delegateclick' on the target.
event.target.dispatchEvent(new CustomEvent('delegateEvent'));
}
}
在第 1 阶段和第 2 阶段,只有 1 个警告,那就是;如果您在 day.component.html 中嵌套了子元素,您将需要为此实现冒泡,在该 if 语句中实现更好的逻辑,或者快速破解将是......在day.component.css :host *{pointer-events: none;}
现在我们需要告诉 day.component 期待我们的
delegateEvent 事件。所以在
day.component.ts 中,你所要做的(以最有角度的方式)就是......
@HostListener('delegateEvent', ['$event'])
public onEvent() {
console.log("i've been clicked via a delegate!");
}
这是可行的,因为 typescript 不关心事件是否是原生的,它只会将一个新的 javascript 事件绑定到元素,因此允许我们通过event.target.dispatchEvent“原生”调用它,就像我们在上面所做的那样month.component.ts.
第 1 阶段结束,我们现在成功地将活动从我们的月份委派到我们的日子。
第 2 阶段
如果我们说想在day.component 内的委托事件中运行一点逻辑,然后将其返回给month.component,会发生什么情况 - 这样它就可以在一个非常面向对象的情况下继续使用自己的功能方法?幸运的是,我们可以很容易地实现这一点!
在month.component.ts 更新到以下内容。所改变的只是我们现在将通过事件调用传递一个函数,并且我们定义了回调函数。
@HostListener('click', ['$event'])
public onMonthClick(event) {
if (event.target != this.element.nativeElement) {
event.target.dispatchEvent(new CustomEvent('delegateEvent', { detail: this.eventDelegateCallback}));
}
}
public eventDelegateCallback(data) {
console.log(data);
}
剩下的就是在day.component.ts中调用这个函数...
public onEvent(event) {
// run whatever logic you like,
//return whatever data you like to month.component
event.detail(this.day);
}
不幸的是,我们的回调函数在这里命名有点含糊,但是 typescript 会抱怨该属性不是 CustomEventInit 的已定义对象文字,如果以其他方式命名。
多事件漏斗
这种方法的另一个很酷的事情是,您永远不必定义超过此数量的事件,因为您可以通过此委托汇集所有事件,然后在 day.component.ts 中运行逻辑以按 event.type 过滤。 .
month.component.ts
@HostListener('click', ['$event'])
@HostListener('mouseover', ['$event'])
@HostListener('mouseout', ['$event'])
public onMonthEvent(event) {
if (event.target != this.element.nativeElement) {
event.target.dispatchEvent(new CustomEvent('delegateEvent', { detail: this.eventDelegateCallback }));
}
}
day.component.ts
private eventDelegateCallback: any;
@HostListener('delegateEvent', ['$event'])
public onEvent(event) {
this.eventDelegateCallback = event.detail;
if(event.type == "click"){
// run click stuff
this.eventDelegateCallback(this.day)
}
}