在Web應用的組件是松耦合的情況下,比如需要用戶驗證然后處理授權,即時的通信不總是可行的,因為組件沒有耦合在一起。
例如,如果后端對一個請求返回了狀態碼401(表明一個未經授權的請求),我們期望Web應用不允許用戶停留在當前視圖,在這種情況下,我們希望應用把用戶重定向到登錄或者注冊頁面去。
基于這個邏輯,我們不能從外部告訴控制器設置一個新地址。我們也希望這個功能能覆蓋多個作用域,這樣可以用相同的行為來保護這些作用域。
我們需要另一種方式在它們之間通信。
AngularJS的作用域在本質上是分層次的:它們可以通過父子關系很自然地來回溝通。但通常,作用域是不共享變量的,它們執行的功能往往各不相同,跟在父樹上的位置無關。
在這種情況下,我們可以通過在這個鏈上傳遞事件的方式在作用域之間通信。
什么是事件
如同瀏覽器相應瀏覽器層的事件,比如鼠標點擊、頁面滾動那樣,Angular應用也可以響應Angular事件。這使我們可以在應用層中嵌套的各組件之間進行通信,即使這些組件在創建時并未考慮到其他組件。
注意,Angular事件系統并不與瀏覽器的事件系統相通,這意味著,我們只能在作用域上監聽Angular事件而不是DOM事件。
我們可以認為,事件是在應用中傳播的信息片段,通常(可選)包含了應用中發生的事情的信息。
事件傳播
因為作用域是有層次的,所以我們可以在作用域鏈上傳遞事件。
通常說來,選擇要使用的事件傳遞方式,一個好的經驗法則是:查看將要觸發事件的作用域。如果要通知整個事件系統(允許任意作用域處理這個事件),就要往下廣播。
另一方面,如果要提醒一個全局模塊(為了說),我們最終需要通知高層次的作用域(例如$rootScope),并且需要把事件向上傳遞。
比如,當我們在做路由的時候,“全局”應用狀態需要知道應用當前設置了哪個頁面。另一方面,如果我們是在一個選項卡指令和它的子面板指令之間通信,就需要把事件向下傳。
使用$emit來冒泡事件
要把事件沿著作用域鏈向上派送(從子作用域到父作用域),我們要使用$emit()函數。
//發送一個事件
//當們的用戶以當前user登錄了
scope.$emit(‘user:logged_in’, scope.user);在一個emit()事件函數的調用中,事件從子作用域冒泡到父作用域。在產生事件的作用域之上的所有作用域都會收到這個事件的通知。當想要跟應用的其他部分交流狀態的變更時,我們使用emit()事件函數的調用中,事件從子作用域冒泡到父作用域。在產生事件的作用域之上的所有作用域都會收到這個事件的通知。 當想要跟應用的其他部分交流狀態的變更時,我們使用emit()事件函數的調用中,事件從子作用域冒泡到父作用域。在產生事件的作用域之上的所有作用域都會收到這個事件的通知。當想要跟應用的其他部分交流狀態的變更時,我們使用emit()。如果想要跟rootScope通信,需要rootScope通信,需要rootScope通信,需要emit()這個事件。
$emit()方法帶有兩個參數。
1.name(字符串)
要發出的事件名稱。
2.args(集合)
一個參數的集合,作為對象傳遞到事件監聽器中。
emit()方法返回了一個事件對象從監聽器中發出的一切異常都會傳遞到emit()方法返回了一個事件對象 從監聽器中發出的一切異常都會傳遞到emit()方法返回了一個事件對象從監聽器中發出的一切異常都會傳遞到exceptionHandler服務中。
使用$broadcast向下傳遞事件
要把事件向下傳遞(從父作用域到子作用域),我們使用$broadcast()函數。
//等等,購物車去結賬了
//當購物車在結賬的時候
//下面所有的指令都應當禁用自己
scope.broadcast(′cart:checkingout′,scope.cart);在broadcast('cart:checking_out',scope.cart); 在broadcast(′cart:checkingo?ut′,scope.cart);在broadcast()方法上,每個注冊了監聽器的子作用域都會收到這個信息。事件傳播到所有的指令和當前作用域的間接作用域上,并且一路往下調用每個監聽器。
用了$broadcast()方法之后,就設法取消事件的發送了。
$broadcast()方法自身帶有兩個參數。
1.name(字符串)
要發出的事件名稱
2.args(集合)
一個參數的集合,作為對象傳遞到事件監聽器中。
emit()方法返回了一個事件對象從監聽器中發出的一切異常都會傳遞到emit()方法返回了一個事件對象 從監聽器中發出的一切異常都會傳遞到emit()方法返回了一個事件對象從監聽器中發出的一切異常都會傳遞到exceptionHandler服務中。
事件監聽
要監聽一個事件,我們可以使用$on()方法。這個方法為具有某個特定名稱的事件注冊了一個監聽器。事件名稱就是在Angular中觸發的事件類型。
例如,我們可以在路由變更過程被觸發時,監聽事件:
$scope.on('$routeChangeStart',function(evt, next, current){//一個新的路由被觸發了
});
不管什么時候事件$routeChangeStart被觸發,監聽器都會被調用。
Angular把evt對象作為第一個參數傳給正在監聽的一切事件,不管它是我們自定義的事件還是內置的Angular服務
事件對象
事件對象有以下屬性。
1.targetScope(作用域對象)
這個屬性是發送或者廣播事件的作用域。
2.currentScope(作用域對象)
這個對象包含了當前處理事件的作用域
3.name(字符串)
這個字符串是觸發之后,我們正在處理的事件名稱。
4.stopPropagation(函數)
stopPropagation()函數取消通過$emit觸發的事件的進一步傳播。
5.preventDefault(函數)
preventDefault把defaultPrevented標志設置為true。盡管不能停止事件的傳播,我們可以告訴子作用域無需處理這個事件
6.defaultPrevented(布爾值)
調用preventDefault()會把defaultPrevented設置為true。
$on()函數返回了一個反注冊函數,我們可以調用它來取消監聽器。
事件相關的核心服務
Angular核心框架發送事件,我們監聽之后執行操作。可以用事件來讓自己的Angular對象能在全局事件的不同狀態上與應用交互。
我們用emit()調用的有好幾個事件,它們把事件往上發,更多調用的是emit()調用的有好幾個事件,它們把事件往上發,更多調用的是emit()調用的有好幾個事件,它們把事件往上發,更多調用的是broadcast()事件。
核心系統的emitted事件下面的事件從指令向上發送到包含指令調用的作用域。我們可以使用emitted事件 下面的事件從指令向上發送到包含指令調用的作用域。我們可以使用emitted事件下面的事件從指令向上發送到包含指令調用的作用域。我們可以使用on()在這個鏈網上的任意作用域里監聽這些方法:
$scope.$on('includeContentLoaded',function(evt){});1.$includeContentLoaded$includeContentLoaded事件當ngInclude的內容重新加載時,從ngInclude指令上觸發。2.$includeContentRequested$indeludeContentRequested事件從diaoyongfngInclude的作用域上發送。每次ngInclude的內容被請求時,它都會被發送。3.$viewContentLoaded$viewContentLoaded事件每當ngView內容被重新加載時,從當前ngView作用域上發送.
核心系統的broadcast事件1.broadcast事件 1.broadcast事件1.loacationChangeStart
當Angular從loacation服務對瀏覽器的的地址作更新時,會觸發loacation服務對瀏覽器的的地址作更新時,會觸發loacation服務對瀏覽器的的地址作更新時,會觸發locationChangeStart事件.
2.loacationChangeSuccess當且僅當瀏覽器的地址成功變更,又沒有阻止loacationChangeSuccess 當且僅當瀏覽器的地址成功變更,又沒有阻止loacationChangeSuccess當且僅當瀏覽器的地址成功變更,又沒有阻止locationChangeStart事件的情況下,locationChangeSuccess事件會從locationChangeSuccess事件會從locationChangeSuccess事件會從rootScope事件會從rootScope上廣播出來.3.rootScope上廣播出來. 3.rootScope上廣播出來.3.routeChangeStart
在路由變更發生之前,routeChangeStart事件從routeChangeStart事件從routeChangeStart事件從rootScope發送出來。也就是在路由服務器開始解析路由變更所需的所有依賴項時。