对象之间经过直接方法调用来交互javascript
1)对象A直接调用对象B的某个方法,实现交互;直接方法调用本质上也是属于一种特殊的发送与接受消息,它把发送消息和接收消息合并为一个动做完成;html
方法调用方和被调用方被紧密耦合在一块儿;由于发送消息和接收消息是在一个动做内完成,因此没法作到消息的异步发送和接收;java
2)对象A生成消息->将消息通知给一个事件消息处理器(Observable)->消息处理器经过同步或异步的方式将消息传递给接收者;node
这种方式是经过将消息发送和消息接收拆分为两个过程,经过一个中间者来控制消息是同步仍是异步发送;web
在消息通讯的灵活性方面比较有优点,可是也带来了必定的复杂度。可是复杂度通常能够由框架封装,消息的发送方和接收方仍然能够作到比较简单;浏览器
总的来讲就是一种松耦合的处理,2个对象之间有太多紧密的直接关联,应该要考虑经过消息通讯解耦,从而提升应用程序的可维护性和重用性app
在JS中,消息的通知是经过事件表达的,当代码库增加到必定的规模,就须要考虑将行为和自定义事件进行解耦。框架
了解自定义事件的概念异步
1、jQuery自定义事件ide
jQuery的自定义事件是经过on和one绑定的,而后再经过trigger来触发这个事件
若有三种状况须要分别处理:
jQuery 提供的自定义事件能够引入语义,很好地解决问题
//1. 定义自定义事件 $('#username').on('blank.username', function() { console.log('请不要留空'); }); $('#username').on('notExist.username', function() { console.log('用户名不存在'); }); $('#username').on('success.username', function() { console.log('用户名存在'); }); //2. 触发自定义事件 $('.js-submit').on('click', function() { var username = $('#username').val(); username = $.trim(username); if (username === '') { $('#username').trigger('blank.username'); // 若是 username 为空值,则触发 blank.username 事件 } $.post(url, {username: username}, function(data) { var res = data; if (res.retcode === -1) { $('#username').trigger('notExist.username'); // 若是用户不存在,则触发 notExist.username 事件 } else if (res.retcode === 0) { $('#username').trigger('success.username'); // 若是用户存在,则触发 sucess.username 事件 } }); });
trigger须要处理的问题
1.模拟事件对象,用户模拟处理中止事件冒泡
triger()方法触发事件后,会执行浏览器默认操做。例如:
$("input").trigger("focus");
以上代码不只会触发为input元素绑定的focus事件,也会使input元素自己获得焦点(浏览器默认操做)。
若是只想触发绑定的focus事件,而不想执行浏览器默认操做,可使用jQuery中另外一个相似的非冒泡式方法-triggerHandler()方法。
$container.one("focus",function(){
.....
});
$("input").triggerHandler("focus");
该方法会触发input元素上绑定的特定事件,同时取消浏览器对此事件的默认操做,即文本框指触发绑定的focus事件,不会获得焦点。
请注意这里使用了jQuery 的one 来代替on。这二者的区别在于,one 在触发处理器以后会自动将其删除。
2.区分事件类型,触发标准的浏览器事件 和 自定义事件名绑定的处理程序。
解决方法:事件名称+命名空间
p4.on('click.aaa.ccc',function(e,vv,c){ console.log('p4') }) p4.trigger('click.aaa')
2、javascript的自定义事件
1. 简单的自定义事件
自定义事件到激发这个事件,须要document.createEvent(),event.initEvent(),element.dispatchEvent()这三部,分别是建立事件对象,初始化事件对象,触发事件
<div id="testBox"></div> // 1. 建立事件 var evt = document.createEvent('HTMLEvents'); // 2. 定义事件类型,事件初始化 evt.initEvent('customEvent', true, true); // 3. 在元素上监听事件,绑定监听 var obj = document.getElementById('testBox'); obj.addEventListener('customEvent', function(){ console.log('customEvent 事件触发了'+event.type); }, false);
function foo1(){ addLog("foo1 is excute"); } function foo2(){ addLog("the id is "+idChange.getId()+" now!"); } if(document.createEvent){ //This is for the stand browser. var ev=document.createEvent('HTMLEvents'); ev.initEvent('fakeEvent',false,false); document.addEventListener("fakeEvent",foo1,false); document.addEventListener("fakeEvent",foo2,false); }else if(document.attachEvent){ //This is for the damn IE document.documentElement.fakeEvents = 0; // an expando property document.documentElement.attachEvent("onpropertychange", function(event) { if (event.propertyName == "fakeEvents") { foo1(); } }); document.documentElement.attachEvent("onpropertychange",function(event){ if(event.propertyName == "fakeEvents"){ foo2(); } }); } function addLog(log){ var logDiv=document.getElementById('log'); var p=document.createElement("p"); p.appendChild(document.createTextNode(log)); logDiv.appendChild(p); } var idChange=function(){ var id=1; return {getId:function(){return id;}, setId:function(a){ id=a; if(document.dispatchEvent) document.dispatchEvent(ev); else if(document.attachEvent) document.documentElement.fakeEvents++; //This for IE }} }();
2. 一个完整的事件机制
这个机制支持标准事件和自定义事件的监听,移除监听和模拟触发操做。须要注意的是,为了使到代码的逻辑更加清晰,这里约定自定义事件带有 'custom' 的前缀(例如:customTest,customAlert),demo
/** * @description 包含事件监听、移除和模拟事件触发的事件机制,支持链式调用 * @author Kayo Lee(kayosite.com) * @create 2014-07-24 * */ (function( window, undefined ){ var Ev = window.Ev = window.$ = function(element){ return new Ev.fn.init(element); }; // Ev 对象构建 Ev.fn = Ev.prototype = { init: function(element){ this.element = (element && element.nodeType == 1)? element: document; }, /** * 添加事件监听 * * @param {String} type 监听的事件类型 * @param {Function} callback 回调函数 */ add: function(type, callback){ var _that = this; if(_that.element.addEventListener){ /** * @supported For Modern Browers and IE9+ */ _that.element.addEventListener(type, callback, false); } else if(_that.element.attachEvent){ /** * @supported For IE5+ */ // 自定义事件处理 if( type.indexOf('custom') != -1 ){ if( isNaN( _that.element[type] ) ){ _that.element[type] = 0; } var fnEv = function(event){ event = event ? event : window.event if( event.propertyName == type ){ callback.call(_that.element); } }; _that.element.attachEvent('onpropertychange', fnEv); // 在元素上存储绑定的 propertychange 的回调,方便移除事件绑定 if( !_that.element['callback' + callback] ){ _that.element['callback' + callback] = fnEv; } // 标准事件处理 } else { _that.element.attachEvent('on' + type, callback); } } else { /** * @supported For Others */ _that.element['on' + type] = callback; } return _that; }, /** * 移除事件监听 * * @param {String} type 监听的事件类型 * @param {Function} callback 回调函数 */ remove: function(type, callback){ var _that = this; if(_that.element.removeEventListener){ /** * @supported For Modern Browers and IE9+ */ _that.element.removeEventListener(type, callback, false); } else if(_that.element.detachEvent){ /** * @supported For IE5+ */ // 自定义事件处理 if( type.indexOf('custom') != -1 ){ // 移除对相应的自定义属性的监听 _that.element.detachEvent('onpropertychange', _that.element['callback' + callback]); // 删除储存在 DOM 上的自定义事件的回调 _that.element['callback' + callback] = null; // 标准事件的处理 } else { _that.element.detachEvent('on' + type, callback); } } else { /** * @supported For Others */ _that.element['on' + type] = null; } return _that; }, /** * 模拟触发事件 * @param {String} type 模拟触发事件的事件类型 * @return {Object} 返回当前的 Kjs 对象 */ trigger: function(type){ var _that = this; try { // 现代浏览器 if(_that.element.dispatchEvent){ // 建立事件 var evt = document.createEvent('Event'); // 定义事件的类型 evt.initEvent(type, true, true); // 触发事件 _that.element.dispatchEvent(evt); // IE } else if(_that.element.fireEvent){ if( type.indexOf('custom') != -1 ){ _that.element[type]++; } else { _that.element.fireEvent('on' + type); } } } catch(e){ }; return _that; } } Ev.fn.init.prototype = Ev.fn; })( window );
参考: