AngularJS 事件發(fā)布機(jī)制
問題描述
未讀消息提醒
當(dāng)器具用戶或技術(shù)機(jī)構(gòu)對非強(qiáng)檢器具檢校申請發(fā)布新的意見時,需要對對方進(jìn)行消息通知。
后臺很簡單,本文主要解決前臺遇到的問題。

歷史遺留
這是我的消息遺留下來的統(tǒng)計(jì)未讀消息的指令,用到了緩存superCache。
一眼看去應(yīng)該能發(fā)現(xiàn)這個if...else的問題,第一次請求,將數(shù)據(jù)放到緩存里,之后就一直從緩存中取了,這肯定有問題啊!原來有1條消息,然后點(diǎn)擊查看,然后這個指令仍然是從緩存中取的數(shù)據(jù),還顯示一條。
angular.module('webappApp')
.directive('yunzhiUnReadMessageCount', function(ToMessageService, superCache) {
return {
template: '',
restrict: 'E', // 元素
link: function postLink(scope, element) {
// 判斷緩存中是否存在未讀消息數(shù)量
if (typeof superCache.get('unReadMessageCount') === 'undefined') {
// 獲取當(dāng)前用戶的所有未讀收件消息
ToMessageService.pageReceiveUnReadMessageOfCurrentUser(undefined, function(data) {
// 存入緩存
superCache.put('unReadMessageCount', data.totalElements);
// 顯示文本信息
element.text(superCache.get('unReadMessageCount'));
});
} else {
// 顯示文本信息
element.text(superCache.get('unReadMessageCount'));
}
}
};
});
功能實(shí)現(xiàn)
注銷時清除緩存
注銷時如果不清除緩存,下一個用戶登錄時用的就是上一用戶留下來的緩存,造成信息提示錯誤。

閱讀時重新執(zhí)行指令
下圖就是該實(shí)現(xiàn)的難點(diǎn)。
該用戶有一條未讀消息,當(dāng)用戶點(diǎn)擊閱讀這條消息時,將該消息的狀態(tài)設(shè)置為已讀,然后右上角的未讀條數(shù)同時修改。但是點(diǎn)擊這個事件是發(fā)生在控制器中,而消息又是一個額外的指令,兩者毫無聯(lián)系。

AngularJS的精髓就是Scope,這是兩個Scope,頁面內(nèi)容是我們的控制器Scope,右上角的消息處是我們的未讀消息指令Scope。
如若是簡單的父子Scope關(guān)系,我們可以從控制器傳參數(shù)到指令,指令watch這個參數(shù),根據(jù)控制器對參數(shù)的變動讓指令做出響應(yīng)。但是這兩個Scope毫無關(guān)系,我們怎么辦呢?

事件發(fā)布
查閱了相關(guān)資料,AngularJS中Scope可以發(fā)布事件。
$broadcast(name, args);
Dispatches an event name downwards to all child scopes (and their children) notifying the registered $rootScope.Scope listeners.
向下分發(fā)一個事件給他的所有子Scope,通知已注冊的Scope。
$emit(name, args);
Dispatches an event name upwards through the scope hierarchy notifying the registered $rootScope.Scope listeners.
與$broadcast類似,只不過這個是用來向上發(fā)布事件的。
$on(name, listener);
Listens on events of a given type.
監(jiān)聽一個給定類型的事件。
實(shí)例說明angularjs $broadcast $emit $on的用法
<div ng-controller="ParentCtrl"> //父級
<div ng-controller="SelfCtrl"> //自己
<a ng-click="click()">click me</a>
<div ng-controller="ChildCtrl"></div> //子級
</div>
<div ng-controller="BroCtrl"></div> //平級
</div>
js代碼
appControllers.controller('SelfCtrl', function($scope) {
$scope.click = function () {
$scope.$broadcast('to-child', 'child');
$scope.$emit('to-parent', 'parent');
}
});
appControllers.controller('ParentCtrl', function($scope) {
$scope.$on('to-parent', function(d,data) {
console.log(data); //父級能得到值
});
$scope.$on('to-child', function(d,data) {
console.log(data); //子級得不到值
});
});
appControllers.controller('ChildCtrl', function($scope){
$scope.$on('to-child', function(d,data) {
console.log(data); //子級能得到值
});
$scope.$on('to-parent', function(d,data) {
console.log(data); //父級得不到值
});
});
appControllers.controller('BroCtrl', function($scope){
$scope.$on('to-parent', function(d,data) {
console.log(data); //平級得不到值
});
$scope.$on('to-child', function(d,data) {
console.log(data); //平級得不到值
});
});
點(diǎn)擊Click me的輸出結(jié)果
child
parent
代碼實(shí)現(xiàn)
$rootScope
考慮到這兩個控制器與指令之間Scope的關(guān)系,無論是向上還是向下可能都接收不到。
這里直接用$rootScope向下發(fā)布事件,保證所有Scope都能獲取到該事件。免得去考慮當(dāng)前Scope與目的Scope之間的關(guān)系。
// 廣播發(fā)布reloadMessageCount事件,重新計(jì)算未讀消息數(shù)量
$rootScope.$broadcast('reloadMessageCount');
因?yàn)榭紤]到各個層之間的職責(zé)關(guān)系,我認(rèn)為:事件發(fā)布應(yīng)該方法控制器中,而不應(yīng)該放在Service中,Service就等著被別人調(diào)用,不應(yīng)該與其他文件有耦合關(guān)系,否則改起來很難改。
$on
重構(gòu)指令,使用$on監(jiān)聽事件發(fā)布,執(zhí)行相應(yīng)的邏輯重新顯示右上角的未讀消息數(shù)。
angular.module('webappApp')
.directive('yunzhiUnReadMessageCount', function(ToMessageService, superCache) {
return {
template: '<b ng-if="count">{{ count }}</b>',
restrict: 'E', // 元素
link: function postLink(scope) {
var self = this;
self.init = function() {
self.computeMessageCount();
};
// 計(jì)算未讀消息數(shù)量
self.computeMessageCount = function() {
// 判斷緩存中是否存在未讀消息數(shù)量
if (angular.isUndefined(superCache.get('unReadMessageCount'))) {
// 獲取當(dāng)前用戶的所有未讀收件消息
ToMessageService.pageReceiveUnReadMessageOfCurrentUser(undefined, function(data) {
// 存入緩存
superCache.put('unReadMessageCount', data.totalElements);
// 顯示
scope.count = superCache.get('unReadMessageCount');
});
} else {
scope.count = superCache.get('unReadMessageCount');
}
};
// 處理reloadMessageCount事件的處理邏輯
scope.$on('reloadMessageCount', function() {
// 清除緩存
superCache.remove('unReadMessageCount');
// 計(jì)算未讀消息數(shù)量
self.computeMessageCount();
});
// 初始化
self.init();
}
};
});

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Angular使用ControlValueAccessor創(chuàng)建自定義表單控件
這篇文章主要介紹了Angular使用ControlValueAccessor創(chuàng)建自定義表單控件,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-03-03
淺談Angular4實(shí)現(xiàn)熱加載開發(fā)旅程
本篇文章主要介紹了淺談Angular4實(shí)現(xiàn)熱加載開發(fā)旅程,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-09-09
angularjs在ng-repeat中使用ng-model遇到的問題
本文給大家分享了一個個人在使用angular過程中遇到的在ng-repeat中使用ng-model的問題,并附上簡單的解決辦法,希望能對大家學(xué)習(xí)angular有所幫助2016-01-01
AngularJS實(shí)現(xiàn)Input格式化的方法
這篇文章主要介紹了AngularJS實(shí)現(xiàn)Input格式化的方法,結(jié)合實(shí)例形式分析了AngularJS實(shí)現(xiàn)Input格式化的操作步驟與相關(guān)注意事項(xiàng),需要的朋友可以參考下2016-11-11
詳解AngularJS用Interceptors來統(tǒng)一處理HTTP請求和響應(yīng)
本篇文章主要介紹了AngularJS用Interceptors來統(tǒng)一處理HTTP請求和響應(yīng) ,具有一定的參考價(jià)值,有興趣的可以了解一下2017-06-06
Angular5中提取公共組件之radio list的實(shí)例代碼
這篇文章主要介紹了Angular5中提取公共組件之radio list的實(shí)例代碼,非常不錯,具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-07-07
angular 實(shí)時監(jiān)聽input框value值的變化觸發(fā)函數(shù)方法
今天小編就為大家分享一篇angular 實(shí)時監(jiān)聽input框value值的變化觸發(fā)函數(shù)方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-08-08
Angular5中調(diào)用第三方j(luò)s插件的方法
下面小編就為大家分享一篇Angular5中調(diào)用第三方j(luò)s插件的方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-02-02
AngularJS框架的ng-app指令與自動加載實(shí)現(xiàn)方法分析
這篇文章主要介紹了AngularJS框架的ng-app指令與自動加載實(shí)現(xiàn)方法,結(jié)合實(shí)例形式分析了ng-app指令的功能及自動加載機(jī)制的實(shí)現(xiàn)技巧,需要的朋友可以參考下2017-01-01
AngularJS ng-bind-template 指令詳解
本文注意介紹AngularJS ng-bind-template 指令,這里把相關(guān)資料整理了一下,并附實(shí)例代碼,有需要的小伙伴可以參考下2016-07-07

