Mic*_*zyk 15 javascript typescript angular2-template angular
我正在开发一个ng2应用程序,我正在努力解决问题.我建立一个日历,您可以选择一个日期范围,我需要作出反应上click
与mouseenter/mouseleave
上一天的细胞活动.所以我有一个像这样的代码(简化):
calendar.component.html
<month>
<day *ngFor="let day of days" (click)="handleClick()"
(mouseenter)="handleMouseEnter()"
(mouseleave)="handleMouseLeave()"
[innerHTML]="day"></day>
</month>
Run Code Online (Sandbox Code Playgroud)
但是这给了我数百个独立的事件监听器在浏览器的内存中(每天的单元格获得3个事件监听器,我一次最多可以显示12个月,因此它将超过1k的监听器).
因此,我希望使用名为"事件委托"的方法"正确的方式".我的意思是,在父组件(month
)上附加一个click事件,当它收到一个click事件时,只需检查它是否在Day
组件上发生- 然后我就会对这个点击作出反应.当你传递参数时,像jQuery这样的东西在on()方法中selector
.
但我是通过在处理程序代码中原生地引用DOM元素来实现的:
month.component.ts
private handleClick(event) {
if (event.target.tagName === 'DAY') {
// handle day click
} else {
// handle other cases
}
}
Run Code Online (Sandbox Code Playgroud)
我的同事拒绝了我的想法,因为 - 正如他们所说的那样 - "在NG2中必须有一种更简单,更恰当的方法来处理这个问题;就像在jQuery中一样.此外,它在这里失控 - 你对Day的点击做出反应在月的代码中."
所以,我的问题是,有更好的方法吗?或者我是否正在尝试解决一个我不应该再费心解决的问题,因为用户的设备每天都会获得越来越多的内存/处理能力?
提前致谢!
介绍
我今天偶然发现了这一点,我确实可以在很多应用程序中看到这种实现的必要性。现在我不能保证这是 100% 最好的技术,但是我已经竭尽全力使这种方法尽可能地受到角度启发。
我提出的方法有两个阶段。第 1 阶段和第 2 阶段总计都会增加years * months + years * months * days
,因此在 1 年内您将有12 + 365
事件。
第 1 阶段:将单击月份时的事件委托到单击的实际日期,而不要求当天发生事件。
第 2 阶段:将所选日期传播回月份。
在深入研究之前,该应用程序由 3 个组件组成,这些组件按以下顺序嵌套:app => month => day
这就是所需的全部 html。app.component 托管多个月份,month.component 托管多个天,而 day.component 不执行任何操作,只是将日期显示为文本。
应用程序组件.html
<app-month *ngFor="let month of months" [data-month]="month"></app-month>
Run Code Online (Sandbox Code Playgroud)
月.component.html
<app-day *ngFor="let day of days" [data-day]="day">{{day}}</app-day>
Run Code Online (Sandbox Code Playgroud)
day.component.html
<ng-content></ng-content>
Run Code Online (Sandbox Code Playgroud)
这是相当标准的东西。
阶段1
让我们看看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'));
}
}
Run Code Online (Sandbox Code Playgroud)
在第一阶段和第二阶段中,只有1个警告:如果您在 中嵌套了子元素day.component.html
,则需要为此实现冒泡,在 if 语句中实现更好的逻辑,或者快速破解......day.component.css
:host *{pointer-events: none;}
delegateEvent
事件。所以day.component.ts
你所要做的就是(以尽可能最有角度的方式)......
@HostListener('delegateEvent', ['$event'])
public onEvent() {
console.log("i've been clicked via a delegate!");
}
Run Code Online (Sandbox Code Playgroud)
这是有效的,因为 typescript 不关心事件是否是本机的,它只会将一个新的 javascript 事件绑定到元素,从而允许我们event.target.dispatchEvent
像上面在month.component.ts
.
第一阶段到此结束,我们现在成功地将每月的活动委托给每天的活动。
那么,如果我们说想要在委托事件中运行一点逻辑,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);
}
Run Code Online (Sandbox Code Playgroud)
剩下的就是在day.component.ts
...... 中调用这个函数。
public onEvent(event) {
// run whatever logic you like,
//return whatever data you like to month.component
event.detail(this.day);
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,我们的回调函数在这里的命名有点含糊,但是如果以其他方式命名,打字稿会抱怨该属性不是定义的对象文字CustomEventInit
。
这种方法的另一个很酷的事情是,您永远不必定义超过此数量的事件,因为您可以通过此委托汇集所有事件,然后在其中运行逻辑day.component.ts
来过滤event.type
...
月份.组件.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 }));
}
}
Run Code Online (Sandbox Code Playgroud)
日组件.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)
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1549 次 |
最近记录: |