ホームページ  >  記事  >  ウェブフロントエンド  >  カスタムイベントのJavaScript実装の詳しい説明_JavaScriptスキル

カスタムイベントのJavaScript実装の詳しい説明_JavaScriptスキル

WBOY
WBOYオリジナル
2016-05-16 15:19:211225ブラウズ

DOM を操作するときは、通常、onclick、onmouseover、および一連のブラウザー固有の動作イベントを使用します。 したがって、カスタム イベントは、その名前が示すように、独自のイベント タイプとイベント処理関数を定義し、適切なタイミングでどのイベント タイプが必要かを呼び出すことができます。

1.js でサポートされるブラウザのデフォルト イベント

特定のブラウザーの動作に関するイベント、またはシステム イベント、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("你点击了我");
});

あまり詳しくは調べませんが、ここでは js のカスタム イベントについて説明します。js のデフォルト イベントを処理するために以前にカプセル化したコードを次に示します。

次のトピック、js カスタム イベントに進みましょう
//跨浏览器的事件处理程序 
//调用时候直接用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 カスタム イベントをカプセル化します

上記のパッケージによれば、次のように考えることができます

これは誰にとっても理解しやすいと思いますが、次に考えられる別の質問があります。それは、JS のデフォルト イベント、JS は 1 対 1 に対応できます。どれがそれであるかはわかりますが、その後はどうなるでしょうか。カスタム イベント、これを 1 つずつ対応するマッピング テーブルは自分たちでのみ確立できます。その後、これを実行します
var eventTarget = {
  addEvent: function(){
    //添加事件
  },
  fireEvent: function(){
    //触发事件
  },
  removeEvent: function(){
    //移除事件
  }
};

これがこのマッピング関係を構築した方法です
var eventTarget = {
  //保存映射
  handlers:{},
  addEvent: function(){
    //处理代码
  },
  fireEvent: function(){
    //触发代码
  },
  removeEvent: function(){
    //移出代码
  }
};

このようにして、各タイプに複数の処理機能を持たせて、将来の拡張を容易にすることができます
handlers = {
  "type1":[
    "fun1",
    "fun2",
    // "..."
  ],
  "type2":[
    "fun1",
    "fun2"
    // "..."
  ]
  //"..."
}
次は実際のコーディング面で、具体的な処理コードを記述します...

このアイデアについては皆さんすでによく理解されていると思います。コードを直接添付します

これは run を呼び出すメソッドです
//直接量处理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"});  //空

要約: リテラル メソッドにはわずかな欠点があります。つまり、ハンドラー関数で特定の属性を誤って null に割り当てた場合、eventTarget メソッドがクラッシュすることになります。プロトタイピングは良い方法であり、もう少し安全であるべきだと思われます。
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

以上がこの記事の全内容です。皆様の学習のお役に立てれば幸いです。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。