DOM を操作するときは、通常、onclick、onmouseover、および一連のブラウザー固有の動作イベントを使用します。
したがって、カスタム イベントは、その名前が示すように、独自のイベント タイプとイベント処理関数を定義し、適切なタイミングでどのイベント タイプが必要かを呼び出すことができます。
特定のブラウザーの動作に関するイベント、またはシステム イベント、JS デフォルト イベントなどはすべて問題ありません。以下では、これらを JS デフォルト イベントと呼びます。
誰もが、JS のデフォルト イベントのイベント バインディングやイベント削除などの一連の操作を使用したことがあると思います。
//DOM0级事件处理程序 var oDiv = document.getElementById('oDiv'); oDiv.onclick = function(){ alert("你点击了我"); }
//DOM2级事件处理程序 var oDiv = document.getElementById('oDiv'); //非ie oDiv.addEventListener("click",function(){ alert("你点击了我"); },false); //ie oDiv.attachEvent("onclick", function(){ alert("你点击了我"); });
//跨浏览器的事件处理程序 //调用时候直接用domEvent.addEvent( , , );直接调用 //使用时候,先用addEvent添加事件,然后在handleFun里面直接写其他函数方法,如getEvent; //addEventListener和attachEvent---都是dom2级事件处理程序 var domEvent = { //element:dom对象,event:待处理的事件,handleFun:处理函数 //事件名称,不含“on”,比如“click”、“mouseover”、“keydown”等 addEvent:function(element,event,handleFun){ //addEventListener----应用于mozilla if(element.addEventListener){ element.addEventListener(event,handleFun,false); }//attachEvent----应用于IE else if(element.attachEvent){ element.attachEvent("on"+event,handleFun); }//其他的选择dom0级事件处理程序 else{ //element.onclick===element["on"+event]; element["on"+event] = handleFun; } }, //事件名称,含“on”,比如“onclick”、“onmouseover”、“onkeydown”等 removeEvent:function(element,event,handleFun){ //removeEventListener----应用于mozilla if (element.removeEventListener) { element.removeEventListener(event,handleFun,false); }//detachEvent----应用于IE else if (element.detachEvent) { element.detachEvent("on"+event,handleFun); }//其他的选择dom0级事件处理程序 else { element["on"+event] = null; } }, //阻止事件冒泡 stopPropagation:function(event){ if(event.stopPropagation){ event.stopPropagation(); }else{ event.cancelBubble = true;//IE阻止事件冒泡,true代表阻止 } }, //阻止事件默认行为 preventDefault:function(event){ if(event.preventDefault){ event.preventDefault(); }else{ event.returnValue = false;//IE阻止事件冒泡,false代表阻止 } }, //获得事件元素 //event.target--非IE //event.srcElement--IE getElement:function(event){ return event.target || event.srcElement; }, //获得事件 getEvent:function(event){ return event? event : window.event; }, //获得事件类型 getType:function(event){ return event.type; } };
2. オブジェクト リテラルは JS カスタム イベントをカプセル化します
上記のパッケージによれば、次のように考えることができます
var eventTarget = { addEvent: function(){ //添加事件 }, fireEvent: function(){ //触发事件 }, removeEvent: function(){ //移除事件 } };
var eventTarget = { //保存映射 handlers:{}, addEvent: function(){ //处理代码 }, fireEvent: function(){ //触发代码 }, removeEvent: function(){ //移出代码 } };
handlers = { "type1":[ "fun1", "fun2", // "..." ], "type2":[ "fun1", "fun2" // "..." ] //"..." }
このアイデアについては皆さんすでによく理解されていると思います。コードを直接添付します
//直接量处理js自定义事件 var eventTarget = { //保存事件类型,处理函数数组映射 handlers:{}, //注册给定类型的事件处理程序, //type -> 自定义事件类型, handler -> 自定义事件回调函数 addEvent: function(type, handler){ //判断事件处理数组是否有该类型事件 if(eventTarget.handlers[type] == undefined){ eventTarget.handlers[type] = []; } //将处理事件push到事件处理数组里面 eventTarget.handlers[type].push(handler); }, //触发一个事件 //event -> 为一个js对象,属性中至少包含type属性, //因为类型是必须的,其次可以传一些处理函数需要的其他变量参数。(这也是为什么要传js对象的原因) fireEvent: function(event){ //判断是否存在该事件类型 if(eventTarget.handlers[event.type] instanceof Array){ var _handler = eventTarget.handlers[event.type]; //在同一个事件类型下的可能存在多种处理事件,找出本次需要处理的事件 for(var i = 0; i < _handler.length; i++){ //执行触发 _handler[i](event); } } }, //注销事件 //type -> 自定义事件类型, handler -> 自定义事件回调函数 removeEvent: function(type, handler){ if(eventTarget.handlers[type] instanceof Array){ var _handler = eventTarget.handlers[type]; //在同一个事件类型下的可能存在多种处理事件,找出本次需要处理的事件 for(var i = 0; i < _handler.length; i++){ //找出本次需要处理的事件下标 if(_handler[i] == handler){ break; } } //删除处理事件 _handler.splice(i, 1); } } };
eventTarget.addEvent("eat",function(){ console.log(123); //123 }); eventTarget.fireEvent({type: "eat"});
function b(){ console.log(123); } eventTarget.addEvent("eat",b); eventTarget.fireEvent({ type: "eat" }); //123 eventTarget.removeEvent("eat",b); eventTarget.fireEvent({type: "eat"}); //空
eventTarget.fireEvent({ type: "eat", food: "banana" }); function b(data){ console.log(data.food); //banana }
3. オブジェクト プロトタイプは JS カスタム イベントをカプセル化します
前のアイデアは基本的にわかりやすく説明されているので、ここにコードを直接添付します。メリットとデメリットを検討して、より良い解決方法を見つけることができるかもしれません...
//自定义事件构造函数 function EventTarget(){ //事件处理程序数组集合 this.handlers = {}; } //自定义事件的原型对象 EventTarget.prototype = { //设置原型构造函数链 constructor: EventTarget, //注册给定类型的事件处理程序, //type -> 自定义事件类型, handler -> 自定义事件回调函数 addEvent: function(type, handler){ //判断事件处理数组是否有该类型事件 if(typeof this.handlers[type] == 'undefined'){ this.handlers[type] = []; } //将处理事件push到事件处理数组里面 this.handlers[type].push(handler); }, //触发一个事件 //event -> 为一个js对象,属性中至少包含type属性, //因为类型是必须的,其次可以传一些处理函数需要的其他变量参数。(这也是为什么要传js对象的原因) fireEvent: function(event){ //模拟真实事件的event if(!event.target){ event.target = this; } //判断是否存在该事件类型 if(this.handlers[event.type] instanceof Array){ var handlers = this.handlers[event.type]; //在同一个事件类型下的可能存在多种处理事件,找出本次需要处理的事件 for(var i = 0; i < handlers.length; i++){ //执行触发 handlers[i](event); } } }, //注销事件 //type -> 自定义事件类型, handler -> 自定义事件回调函数 removeEvent: function(type, handler){ //判断是否存在该事件类型 if(this.handlers[type] instanceof Array){ var handlers = this.handlers[type]; //在同一个事件类型下的可能存在多种处理事件 for(var i = 0; i < handlers.length; i++){ //找出本次需要处理的事件下标 if(handlers[i] == handler){ break; } } //从事件处理数组里面删除 handlers.splice(i, 1); } } };
function b(){ console.log(123); } var target = new EventTarget(); target.addEvent("eat", b); target.fireEvent({ type: "eat" }); //123