一不小心翻车了-(angularjs 1.6X) 由Eventbus使用异常说起
Posted 阿拉蕾家的小铁匠
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一不小心翻车了-(angularjs 1.6X) 由Eventbus使用异常说起相关的知识,希望对你有一定的参考价值。
一 在angular框架使用过程中,我们经常碰到控制器之间进行通信的问题,
方法有多种,今天记录的是通过factory通信,先上代码:
//控制器之间共享 angular.module(‘app‘).factory("EventBus", function() { var eventMap = {}; var EventBus = { on : function(eventType, handler) { if (!eventMap[eventType]) { eventMap[eventType] = []; } eventMap[eventType].push(handler); }, off : function(eventType, handler) { for (var i = 0; i < eventMap[eventType].length; i++) { if (eventMap[eventType][i] === handler) { eventMap[eventType].splice(i, 1); break; } } },
fire : function(event) { var eventType = event.type; if (eventMap && eventMap[eventType]) { for (var i = 0; i < eventMap[eventType].length; i++) { eventMap[eventType][i](event); } } } }; return EventBus; });
调用发布事件时候
angular.module(‘app‘).controller(‘testcontroller‘,function($scope,$state,EventBus) { //发布事件 EventBus.fire({ type:‘testevent‘, data:{ List:1 } }) });
调用监事件听时候
angular.module(‘app‘).controller(‘testcontroller‘,function($scope,$state,EventBus) { EventBus.on("testevent",function(event){ var data=event.data; console.log(data); }); });
这个方法可以在多个地方监听同一个事件,代码又简练,在项目中用的很舒服
二 但是用起来之后问题来了,主要有2个BUG
第一个就是off取消事件
off : function(eventType, handler) { for (var i = 0; i < eventMap[eventType].length; i++) { //这个判断对比的是2个函数,永远都是false if (eventMap[eventType][i] === handler) { eventMap[eventType].splice(i, 1); break; } } },
取消时判断对比的是2个函数,永远都是false。 这个问题简单的解决方法就是把2个函数转化成string 再对比
代码如下
off : function(eventType, handler) { for (var i = 0; i < eventMap[eventType].length; i++) { if (eventMap[eventType][i].toString() === handler.toString()) { eventMap[eventType].splice(i, 1); break; } } },
更完善的函数比较可以引用函数对比函数
/** * 返回指定变量的数据类型 * @param {Any} data * @return {String} */ function type (data) { return Object.prototype.toString.call(data).slice(8, -1); } /** * 对比两个function是否一样 * 主要对比两者toString是否一样, * 对比会去掉函数名进行对比,其它哪怕差个回车都会返回false * * @param {[type]} fn1 * @param {[type]} fn2 * @return {[type]} */ function equalFunction (fn1, fn2) { var type1 = type(fn1), type2 = type(fn2); console.log(type1,type2) if (type1 !== type2 || type1 !== ‘Function‘) { return false; }; if (fn1 === fn2) { return true; }; var reg = /^function[\s]*?([\w]*?)\([^\)]*?\){/; var str1 = fn1.toString().replace(reg,function ($,$1) { return $.replace($1,""); }); var str2 = fn2.toString().replace(reg,function ($,$1) { return $.replace($1,""); }); console.log(str1,str2); if (str1 !== str2) { return false; }; return true; } off : function(eventType, handler) { for (var i = 0; i < eventMap[eventType].length; i++) { //if (eventMap[eventType][i] === handler) { if (equalFunction(eventMap[eventType][i],handler)) { //if (eventMap[eventType][i].toString() === handler.toString()) { eventMap[eventType].splice(i, 1); break; } } },
这个解决方案相对比较完善一些
三 第二个Bug就比较致命了
一开始我发现on监听执行过程中 获取的$scope 变量的值不是最新的!!! 差点让我怀疑人生。
仔细研究之后发现同一个on监听执行了好多次(呵呵哒)
原因在于 通信监听的on事件 注册了多次!!!
注册多次是由于on所在的controller对应的页面 通过$state.go可跳转至其它页面 也可以跳转回来
跳转回来多次 同一个on监听就被注册了多次 ,而且每次的on监听封装的$scope变量都是当次跳转到其它页面之前的值
最后fire事件发布时,on就会有多个监听依次之下(同一个on监听事件 执行多次 但是每次的$scope变量可能不一样)
so........我们在注册on事件时候需要查看下是否已经注册过该事件了 。。。。然后删除旧的 注册最新的(封装了最新的$scope变量)
代码
on : function(eventType, handler) { if (!eventMap[eventType]) { eventMap[eventType] = []; } //注册on事件时候需要查看下是否已经注册过该事件了 。。。。然后删除旧的 注册最新的(封装了最新的$scope变量) this.off(eventType, handler); eventMap[eventType].push(handler); },
四 修复Bug之后 开车的代码如下 又可以愉快的发车咯
//控制器之间共享 angular.module(‘yun.homework‘).factory("EventBus", function() { var eventMap = {}; /** * 返回指定变量的数据类型 * @param {Any} data * @return {String} */ function type (data) { return Object.prototype.toString.call(data).slice(8, -1); } /** * 对比两个function是否一样 * 主要对比两者toString是否一样, * 对比会去掉函数名进行对比,其它哪怕差个回车都会返回false * * @param {[type]} fn1 * @param {[type]} fn2 * @return {[type]} */ function equalFunction (fn1, fn2) { var type1 = type(fn1), type2 = type(fn2); console.log(type1,type2) if (type1 !== type2 || type1 !== ‘Function‘) { return false; }; if (fn1 === fn2) { return true; }; var reg = /^function[\s]*?([\w]*?)\([^\)]*?\){/; var str1 = fn1.toString().replace(reg,function ($,$1) { return $.replace($1,""); }); var str2 = fn2.toString().replace(reg,function ($,$1) { return $.replace($1,""); }); console.log(str1,str2); if (str1 !== str2) { return false; }; return true; } var EventBus = { on : function(eventType, handler) { if (!eventMap[eventType]) { eventMap[eventType] = []; } this.off(eventType, handler); eventMap[eventType].push(handler); }, off : function(eventType, handler) { for (var i = 0; i < eventMap[eventType].length; i++) { //if (eventMap[eventType][i] === handler) { //if (equalFunction(eventMap[eventType][i],handler)) { if (eventMap[eventType][i].toString() === handler.toString()) { eventMap[eventType].splice(i, 1); break; } } }, fire : function(event) { var eventType = event.type; if (eventMap && eventMap[eventType]) { for (var i = 0; i < eventMap[eventType].length; i++) { eventMap[eventType][i](event); } } } }; return EventBus; });
以上是关于一不小心翻车了-(angularjs 1.6X) 由Eventbus使用异常说起的主要内容,如果未能解决你的问题,请参考以下文章
AngularJS 1.6 升级代码以登录不再使用 REST?
AngularJS 1.6 + ES6 - $doCheck 被调用两次
将 AngularJs 1.5 升级到 1.6 - $compile reg 控制器实例的更改会影响哪些确切的绑定?