2016-07-06 45 views
13

我正在ng2中開發一個應用程序,而且我正在努力尋找一些東西。我正在製作一個日曆,您可以選擇一個日期範圍,並且需要對日間單元格上的事件做出反應。所以我有一個代碼(簡化)這樣的:Angular2中的事件代表團

calendar.component.html

<month> 
    <day *ngFor="let day of days" (click)="handleClick()" 
     (mouseenter)="handleMouseEnter()" 
     (mouseleave)="handleMouseLeave()" 
     [innerHTML]="day"></day> 
</month> 

但是這給了我幾百個單獨的事件監聽器在瀏覽器的內存(每一天的細胞得到3個事件監聽器,我可以一次顯示12個月的時間,所以它會超過1K的聽衆)。

所以我想用「事件委託」的方法做到「正確的方式」。我的意思是,在父組件上附加一個點擊事件(month),當它收到點擊事件時,只需檢查它是否發生在Day組件上 - 然後我會對此點擊作出反應。當你傳遞參數selector時,像jQuery那樣在on() method中。

但是我被本地引用DOM元素的處理程序的代碼,這樣做:

month.component.ts

private handleClick(event) { 
    if (event.target.tagName === 'DAY') { 
     // handle day click 
    } else { 
     // handle other cases 
    } 
} 

和我的同事拒絕了我的想法,因爲 - 因爲他們說「在NG2中必須有一種更簡單,適當的方式來處理這個問題,就像jQuery中的一樣,此外,它在這裏失控 - 你對Day的代碼中Day的點擊做出了反應。

所以,我的問題是,有沒有更好的方法?或者我正試圖解決一個我不應該再煩惱的問題,因爲用戶的設備每天都會獲得越來越多的內存/處理能力?

在此先感謝!

+1

有獨立的模塊,其處理此。我發現「dom-delegate」工作得很好。就我所知,在ng2中沒有內置任何東西。 – Chrillewoodz

+1

如果這是一個問題......這將是一個角度優化問題。您不必擔心彙總事件以進行優化。 –

+1

幾個月前我遇到了類似的問題,據我所知,您所描述的方法是以原始角度執行此操作的最佳方法。使用較少的事件偵聽器檢查點擊目標。我建議的唯一的事情就是把邏輯放在一個服務或指令中(指令可能會更好,因爲你需要每個月div),這樣代碼是乾淨的並且與組件分離。畢竟,它是html邏輯,而不是組件邏輯 – FussinHussin

回答

1

介紹

我今天這個偶然發現,我真的可以看到在很多應用中,這種執行的需要。現在我不能保證這是100%最好的技術,但是我儘量讓這種方法儘可能地具有靈活性。

我提出的方法有兩個階段。第一階段和第二階段將增加總數爲years * months + years * months * days,因此在1年內您將有12 + 365事件。


舞臺範圍

第一階段:當一個月下來點擊進入實際的一天代表事件,被點擊,而無需在當天的事件。
階段2:將選定的日期傳播回月份。

只是在深入研究之前,該應用程序由被嵌套在下面的順序3個組成部分:app => month => day


這是所有需要的HTML。應用程序。組件託管幾個月,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> 

這是相當股票標準的東西。


第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')); 
    } 
} 

在這兩個階段1和2,有只有 1級的警告,並且是;如果你嵌套了您的day.component.html內子元素,你要麼需要實現冒泡爲此,更好的邏輯,如果陳述,或快速黑客會。在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!"); 
} 

這工作,因爲打字稿不關心該事件是否是天然的或沒有,它只是綁定新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); 
} 

不幸的是我們的回調函數有點含糊這裏命名,但是打字稿會抱怨,如果命名,否則不被定義的對象字面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) 
    } 
    } 
+0

要麼我不理解你的概念,要麼你誤解了我試圖實現的目標。我想只有N個事件監聽器,其中N是個月數。您的方法創建與DayComponents上的HostBinding單擊事件完全相同的事件偵聽器數量。只是你綁定了自定義事件。 –

+0

然而,多項活動確實可以帶來利潤:) –

+0

@MichalLeszczyk它並不完全符合N標記,但是是一項重大改進,並且在添加新事件類型時也不會呈指數增長。這不是完美的,但我認爲它是在正確的軌道上! – Zze