ホームページ > ウェブフロントエンド > jsチュートリアル > JavaScriptイベントバインディング学習のポイント_基礎知識

JavaScriptイベントバインディング学習のポイント_基礎知識

WBOY
リリース: 2016-05-16 15:11:31
オリジナル
1088 人が閲覧しました

イベント バインディングは 2 つのタイプに分けられます。1 つは従来のイベント バインディング (インライン モデル、スクリプト モデル)、もう 1 つは最新のイベント バインディング (DOM2 レベル モデル) です。最新のイベント バインディングは、従来のバインディングよりも強力で便利な機能を提供します。

1 従来のイベント バインディングの問題

従来のイベント バインディングのインライン モデルについては説明されず、ほとんど使用されません。まず、スクリプト モデルを見てみましょう。スクリプト モデルは、関数をイベント処理関数に割り当てます。以下のような従来のバインディング:

window.onload=function(){
 var box=document.getElementById('box');
 box.onclick = function(){
  alert('Lee');
 };
};



ログイン後にコピー

問題 1: イベント処理関数が 2 つのイベントをトリガーする

ページに 2 つ以上の js があり、最初の js が最初のプログラマーによって開発された場合、2 番目の js は 2 番目のプログラマーによって開発されます。最初の window.onload は

のように上書きされます。
window.onload=function(){
 alert('Lee');
};

window.onload=function(){
 alert('Mr.lee');
} 

ログイン後にコピー

結果が印刷されました、Mr.lee

実際、この問題を解決するには次の 2 つの形式を見てください。
a:

alert(window.onload);//一开始没有注册window.onload,那么就是null

window.onload=function(){
 alert('Lee');
};

alert(window.onload);//如果已经有window.onload,打印的是函数function

window.onload=function(){
 alert('Mr.lee');
} 

ログイン後にコピー

b:

alert(typeof window.onload);//一开始没有window.onolad,旧版火狐显示undefined,新版显示object,

window.onload=function(){
 alert('Lee');
};

alert(typeof window.onload);//如果已经有window.onload,所有浏览器都会显示function

window.onload=function(){
 alert('Mr.lee');
}

ログイン後にコピー

それでは解決策があります。

 window.onload=function(){
 alert('Lee');
};

if(typeof window.onload=='function'){
 var saved=null;//保存上一个事件对象
 saved=window.onload;
}

//saved 就是window.onload,saved()相当于window.onload(),但是window.onload()不能执行的
//所以saved()相当于window.onload=function(){}

window.onload=function(){
 if(saved){
  saved();//执行上一个事件 window.onload=function(){}
 }
 alert('Mr.lee'); //执行本事件
}

ログイン後にコピー

質問 2: イベント スイッチャー
ボックスの ID で div を切り替え、内部の背景の赤と青を直接切り替え、切り替える前にボックスを 1 回ポップアップします。たとえば、

window.onload=function(){
 var box=document.getElementById('box');
 box.className="red";
 box.onclick=function(){
  alert('Lee'); //只执行了一次
  blue.call(this);//通过匿名函数执行某一函数,那么里面的this就是代表的window,所以可以通过call传递
 };
}

function blue(){
 this.className="blue";
 this.onclick=red;
 
}

function red(){
 this.className="red";
 this.onclick=blue;
}

ログイン後にコピー

上記のコードは切り替え機能を実装していますが、ポップアップボックスは一度しか実行されません。

//添加事件函数
//obj相当于window
//type相当于onload
//fn相当于function(){}
function addEvent(obj,type,fn){
 //用于保存上一个事件
 var saved=null;
 if(typeof obj['on'+type]=='function'){
  saved=obj['on'+type];//保存上一个事件
 }
 obj['on'+type]=function(){
  if(saved){
   saved();
  }
  fn.call(this);
 }
 
}
addEvent(window,'load',function(){
 var box=document.getElementById("box");
 //addEvent(box,'click',function(){ //目的达到,每次都执行了,没有被覆盖
 // alert('ss');
 //});
 addEvent(box,'click',blue);
});

function red(){
 this.className="red";
 addEvent(box,'click',blue);
}

function blue(){
 this.className="blue";
 addEvent(box,'click',red);
}

//当不停的切换的时候,浏览器突然卡死,并且报错:too much recursion,太多的递归
//因为积累了太多的保存的事件
//解决方案,就是用完的事件,就立刻移除掉

ログイン後にコピー

上記のコードによると、コメントでエラーが発生しました。解決策は次のとおりです。

//添加事件函数
//obj相当于window
//type相当于onload
//fn相当于function(){}
function addEvent(obj,type,fn){
 //用于保存上一个事件
 var saved=null;
 if(typeof obj['on'+type]=='function'){
  saved=obj['on'+type];//保存上一个事件
 }
 obj['on'+type]=function(){
  if(saved){
   saved();
  }
  fn.call(this);
 }
 
}


//当不停的切换的时候,浏览器突然卡死,并且报错:too much recursion,太多的递归
//因为积累了太多的保存的事件
//解决方案,就是用完的事件,就立刻移除掉


//移除事件函数
function removeEvent(obj,type){
 if(obj['on'+type]){
  obj['on'+type]=null;
 }
}


addEvent(window,'load',function(){
 var box=document.getElementById("box");
 //addEvent(box,'click',function(){ //目的达到,每次都执行了,没有被覆盖
 // alert('ss');
 //});
 addEvent(box,'click',blue);
});

function red(){
 this.className="red";
 removeEvent(this,'click');
 addEvent(box,'click',blue);
}

function blue(){
 this.className="blue";
 removeEvent(this,'click');
 addEvent(box,'click',red);
}

ログイン後にコピー

2 つの W3C イベント処理関数
addEventListener() とremoveEventListener()
W3C イベント処理関数には、addEventListener() と RemoveEventListener() の 2 つがあります。

//W3C には 2 つの追加イベントと削除イベントが付属しています
1. カバレッジの問題、解決されました

window.addEventListener('load',function(){
 alert('Lee');
},false);

window.addEventListener('load',function(){
 alert('Mr.Lee');
},false);

window.addEventListener('load',function(){
 alert('Mrs.Lee');
},false);

ログイン後にコピー

2. 同じ機能をブロックする問題は解決されました

window.addEventListener('load',init,false);
window.addEventListener('load',init,false);
window.addEventListener('load',init,false);
function init(){
 alert('Lee');
}
ログイン後にコピー

3. これを渡して解決することは可能ですか
例 1:

window.addEventListener('load',function(){
 var box=document.getElementById('box');
 box.addEventListener('click',function(){
  alert(this);
 },false);
},false);

ログイン後にコピー

例 2:

window.addEventListener('load',function(){
 var box=document.getElementById('box');
 box.addEventListener('click',blue,false);
},false);

function red(){
 this.className="red";
 this.removeEventListener('click',red,false);
 this.addEventListener('click',blue,false);
}

function blue(){
 this.className="blue";
 this.removeEventListener('click',blue,false);
 this.addEventListener('click',red,false);
}

ログイン後にコピー

4. 追加のメソッドは上書きされますか?

window.addEventListener('load',function(){
 var box=document.getElementById('box');
 box.addEventListener('click',function(){
  alert('Lee');
 },false);
 box.addEventListener('click',blue,false);
},false);
ログイン後にコピー

要約すると、W3C はこれらの問題を完全に解決しており、非常に使いやすいですが、IE8 および以前のブラウザーはそれをサポートしていません。もちろん、IE9 は W3C のこれを完全にサポートしています。 2 つのイベント処理関数。

W3C はバブリングとキャプチャの方法を設定できます。

W3C 標準をサポートするブラウザは、イベントを追加するときに addEventListener(event,fn,useCapture) メソッドを使用します。ベースの 3 番目のパラメーター useCapture は、イベントがイベント キャプチャ中に実行されるか、または実行されるかを設定するために使用されます。イベント発生時 ソーク時に実行されます。 W3C (IE) と互換性のないブラウザでは、attachEvent() メソッドが使用されます。ただし、IE のイベント モデルは、イベントが発生したとき、つまり useCapture が false に等しいときにデフォルトで実行されます。イベントを処理するときは useCapture を false に設定する方が安全であり、ブラウザーの互換性も実現します。

イベントキャプチャフェーズ: イベントは最上位のラベルから開始され、イベントターゲット (ターゲット) がキャプチャされるまで下方向に検索されます。
イベント バブリング ステージ: イベントはイベント ターゲット (ターゲット) から開始され、ページの最上位ラベルまでバブリングします。
イベントの蔓延は阻止できる:
W3c では、stopPropagation() メソッドを使用します
IE で cancelBubble = true を設定します

3. IE イベント処理関数

attachEvent() と detachEvent()
IE は、DOM のメソッドと同様の 2 つのメソッド、attachEvent() と detachEvent() を実装します。どちらのメソッドも同じパラメータ (イベント名と関数) を受け入れます。

これら 2 つの関数セットを使用する場合、まず違いについて説明します。1. IE はキャプチャをサポートせず、バブリングのみをサポートします。2. IE のイベント追加は重複した関数をブロックできません。3. IE の this は、 DOM オブジェクト。 4. 従来のイベントでは、IE はイベント オブジェクトを受け入れることができませんが、attchEvent を使用すると受け入れることができますが、いくつかの違いがあります。

1. カバレッジの問題は解決されましたが、結果は Mrs.Lee、Mr.Lee、そして最後に Lee となりました。

window.attachEvent('onload',function(){
 alert('Lee');
});

window.attachEvent('onload',function(){
 alert('Mr.Lee');
});
window.attachEvent('onload',function(){
 alert('Mrs.Lee');
});

ログイン後にコピー
2. 同じ機能がブロックされる問題は解決されていません。

window.attachEvent('onload',init);
window.attachEvent('onload',init);

function init(){
 alert('Lee');
}

ログイン後にコピー
3. これは通過できますか? いいえ、これはウィンドウのことです。呼び出しメソッドを使用する必要があります。

window.attachEvent('onload',function(){
 var box=document.getElementById('box');
 box.attachEvent('onclick',function(){
  //alert(this===box);
  alert(this===window); //true
 });
});
ログイン後にコピー
次の方法は、window.event.srcElement を渡すことです。コードは次のとおりです:

window.attachEvent('onload',function(){
 var box=document.getElementById('box');
 box.attachEvent('onclick',blue);
});

function red(){
 var that=window.event.srcElement;
 that.className="red";
 that.detachEvent('onclick',red);
 that.attachEvent('onclick',blue);
}

function blue(){
 var that=window.event.srcElement;
 that.className="blue";
 that.detachEvent('onclick',blue);
 that.attachEvent('onclick',red);
}

ログイン後にコピー
4. 追加のメソッドは上書きされますか? それとも一度しか実行できませんか?

従来のバインディングでは、IE は W3C のようなパラメーターの受け渡しを通じてイベント オブジェクトを受け入れることができませんが、attachEvent() を使用して行うことができます。

 window.attachEvent('onload',function(){
 var box=document.getElementById('box');
 box.onclick=function(evt){ //传统方法IE无法通过参数获取evt
  alert(evt);//undefined
 }
 box.attachEvent('onclick',function(evt){
  alert(evt);//object
  alert(evt.type);//click
  alert(evt.srcElement.tagName);//DIV
  alert(window.event.srcElement.tagName);//DIV
 });
});
ログイン後にコピー

ブラウザ間の互換性

クロスブラウザ イベント

function addEvent(obj,type,fn){
 if(obj.addEventListener){
  obj.addEventListener(type,fn,false);
 }else if(obj.attachEvent){
  obj.attachEvent('on'+type,fn);
 }
}
ログイン後にコピー

クロスブラウザ削除イベント

function removeEvent(obj,type,fn){
 if(obj.removeEventListener){
  obj.removeEventListener(type,fn,false);
 }else if(obj.detachEvent){
  obj.detachEvent('on'+type,fn);
 }
}
ログイン後にコピー
ブラウザ間でターゲット オブジェクトを取得します

function getTarget(evt){
 if(evt.target){
  return evt.target;
 }else if(window.event.srcElement){
  return window.event.srcElement;
 }
}
ログイン後にコピー

调用方式:

addEvent(window,'load',function(){
 var box=document.getElementById('box');
 addEvent(box,'click',blue);
});


function red(evt){
 var that=getTarget(evt);
 that.className="red";
 removeEvent(that,'click',red);
 addEvent(that,'click',blue);
}

function blue(evt){
 var that=getTarget(evt);
 that.className="blue";
 removeEvent(that,'click',blue);
 addEvent(that,'click',red);
}

ログイン後にコピー

四.事件对象的其他补充

relatedTarget事件

w3c中的一个relatedTarget事件。
例如:

addEvent(window,'load',function(){
 var box=document.getElementById('box');
 addEvent(box,'mouseover',function(evt){
  alert(evt.relatedTarget); //得到移入box最近的那个DOM对象
 });
 
 addEvent(box,'mouseout',function(evt){
  alert(evt.relatedTarget); //从box移出最近的那个DOM对象
 });
});
ログイン後にコピー

IE提供了两组分别用于移入移出的属性fromElement和toElement,分别对应mouseover和mouseout。

addEvent(window,'load',function(){
 var box=document.getElementById('box');
 addEvent(box,'mouseover',function(){
  alert(window.event.fromElement.tagName); //得到移入box最近的那个DOM对象
 });
 
 addEvent(box,'mouseout',function(){
  alert(window.event.toElement.tagName); //从box移出最近的那个DOM对象
 });
});
ログイン後にコピー

PS:fromElement和toElement如果分别对应相反的鼠标事件,没有任何意义。

剩下要做的就是跨浏览器兼容操作:

function getTarget(evt){
 var e=evt || window.event;
 if(e.srcElment){ //IE
  if(e.type=='mouseover'){
   return e.fromElement.tagName;
  }else if(e.type="mouseout"){
   return e.toElement.tagName;
  }
 }else if(e.relatedTarget){ //w3c
  return e.relatedTarget;
 }
}
ログイン後にコピー

屏蔽跳转操作

取消事件的默认行为有一种不规范的做法,就是返回false。

link.onclick=function(){
 alert('Lee');
 return false;
}
ログイン後にコピー

PS:虽然return false;可以实现这个功能,但是有漏洞。
第一:必须写到最后,这样导致中奖的代码执行后,有可能执行不到return false;
第二:return false 写到最前那么之后的自定义操作就失效了。
所以最好的办法应该是在最前面就阻止默认行为,并且后面的代码还可以执行。

link.onclick=function(evt){
 evt.preventDefault;//w3c,阻止默认行为
 alert('Lee');
}

link.onclick=function(evt){
 window.event.returnValue=false;//IE,阻止默认行为
 alert('Lee');
}

ログイン後にコピー

那么跨浏览器的兼容:

function preDef(evt){
 var e=evt || window.event;
 if(e.preventDefault){
  e.preventDefault();
 }else{
  e.returnValue=false;
 }
}
ログイン後にコピー

右键菜单contextmenu
兼容:

function preDef(evt){
 var e=evt || window.event;
 if(e.preventDefault){
  e.preventDefault();
 }else{
  e.returnValue=false;
 }
}

addEvent(window,"load",function(){
 var body=document.getElementsByTagName('body')[0];
 addEvent(body,'contextmenu',function(evt){
  preDef(evt);
 })
});

ログイン後にコピー

PS:contextmenu事件很常用,这直接导致浏览器兼容性较为稳定。

卸载前事件:beforeunload
这个事件可以帮助在离开本页的时候给出相应的提示,“离开”或者“返回”操作。

addEvent(window,'beforeonload',function(){
 preDef(evt);
});
ログイン後にコピー

鼠标滚轮(mousewheel)和DOMMouseScroll
用于获取鼠标上下滚轮的距离

addEvent(document,'mousewheel',function(evt){ //非火狐
 alert(getWD(evt));
});

addEvent(document,'DOMMouseScroll',function(evt){ //火狐
 alert(getWD(evt));
});

function getWD(evt){
 var e=evt|| window.event;
 if(e.wheelDelta){
  return e.wheelDelta;
 }else if(e.detail){ //火狐
  return -evt.detail*30;
 }
}

ログイン後にコピー

PS:通过浏览器检测可以确定火狐只执行DOMMouseScroll。

DOMContentLoaded事件和readystatechange事件

DOMContentLoaded事件和readystatechange事件,有关DOM加载方面的事件。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート