Maison > Article > interface Web > Points d'apprentissage de liaison d'événement JavaScript_connaissances de base
La liaison d'événements est divisée en deux types : l'une est la liaison d'événements traditionnelle (modèle en ligne, modèle de script) et l'autre est la liaison d'événements moderne (modèle de niveau DOM2). La liaison d'événements moderne offre des fonctions plus puissantes et plus pratiques que la liaison traditionnelle.
1 Problèmes avec la liaison d'événements traditionnelle
Le modèle en ligne dans la liaison d'événements traditionnelle ne sera pas discuté et est rarement utilisé. Jetons d'abord un coup d'œil au modèle de script. Le modèle de script attribue une fonction à une fonction de gestion d'événements. Reliure traditionnelle telle que :
window.onload=function(){ var box=document.getElementById('box'); box.onclick = function(){ alert('Lee'); }; };
Problème 1 : Une fonction de gestion d'événements déclenche deux événements
Si une page contient deux js ou plus et que le premier js est développé par le premier programmeur, le second js est développé par le deuxième programmeur. Le premier window.onload est écrasé, tel que
window.onload=function(){ alert('Lee'); }; window.onload=function(){ alert('Mr.lee'); }
Le résultat vient d'être imprimé Mr.lee
En fait, il existe des moyens de résoudre ce problème. Jetez un œil aux deux formulaires suivants.
une :
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'); }
Il existe donc une solution.
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'); //执行本事件 }
Question 2 : Sélecteur d'événements
Basculez un div avec l'ID de la boîte, laissez l'arrière-plan rouge et bleu à l'intérieur changer directement et faites apparaître la boîte une fois avant de changer, comme :
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; }
Bien que le code ci-dessus implémente la fonction de commutation, la boîte contextuelle n'est exécutée qu'une seule fois.
//添加事件函数 //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,太多的递归 //因为积累了太多的保存的事件 //解决方案,就是用完的事件,就立刻移除掉
Selon le code ci-dessus, une erreur s'est produite dans le commentaire. La solution est la suivante :
//添加事件函数 //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); }
Deux fonctions de gestion des événements du W3C
addEventListener() et removeEventListener()
Il existe deux fonctions de gestion des événements du W3C, addEventListener() et removeEventListener().
//W3C est livré avec deux événements d'ajout et de suppression
1. Problème de couverture, résolu
window.addEventListener('load',function(){ alert('Lee'); },false); window.addEventListener('load',function(){ alert('Mr.Lee'); },false); window.addEventListener('load',function(){ alert('Mrs.Lee'); },false);
2. Le problème du blocage de la même fonction est résolu
window.addEventListener('load',init,false); window.addEventListener('load',init,false); window.addEventListener('load',init,false); function init(){ alert('Lee'); }
3. Est-il possible de passer cela et de le résoudre
Exemple 1 :
window.addEventListener('load',function(){ var box=document.getElementById('box'); box.addEventListener('click',function(){ alert(this); },false); },false);
Exemple 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. Ajoutez une méthode supplémentaire. Sera-t-elle écrasée ou ne pourra-t-elle être exécutée qu'une seule fois ?
window.addEventListener('load',function(){ var box=document.getElementById('box'); box.addEventListener('click',function(){ alert('Lee'); },false); box.addEventListener('click',blue,false); },false);
Le W3C peut définir des méthodes de bouillonnement et de capture.
Les navigateurs prenant en charge la norme W3C utilisent la méthode addEventListener(event,fn,useCapture) lors de l'ajout d'événements. Le troisième paramètre useCapture dans la base est une valeur booléenne, qui est utilisée pour définir si l'événement est exécuté lors de la capture d'événement ou lorsque l'événement se produit. Exécuté lors du trempage. Les navigateurs qui ne sont pas compatibles avec le W3C (IE) utilisent la méthode attachEvent(). Cette méthode n'a pas de paramètres pertinents. Cependant, le modèle d'événement d'IE est exécuté par défaut lorsque l'événement apparaît, c'est-à-dire lorsque useCapture est égal à false, donc. mettez-le dedans Il est plus sûr de définir useCapture sur false lors de la gestion des événements, et cela assure également la compatibilité du navigateur.
Phase de capture d'événement : l'événement commence à partir de l'étiquette de niveau supérieur et recherche vers le bas jusqu'à ce que la cible de l'événement (cible) soit capturée.
Étape de bouillonnement d'événement : l'événement commence à partir de la cible de l'événement (cible) et remonte jusqu'à l'étiquette de niveau supérieur de la page.
La propagation des événements peut être stoppée :
Dans le W3c, utilisez la méthode stopPropagation()
Définissez CancelBubble = true sous IE
3. Fonction de gestion des événements IE
IE implémente deux méthodes similaires à celles du DOM : attachEvent() et detachEvent(). Les deux méthodes acceptent les mêmes paramètres : nom de l'événement et fonction.
1. Le problème de couverture est résolu, mais il y a des différences. Le résultat est Mme Lee, M. Lee et enfin Lee
.
window.attachEvent('onload',function(){ alert('Lee'); }); window.attachEvent('onload',function(){ alert('Mr.Lee'); }); window.attachEvent('onload',function(){ alert('Mrs.Lee'); });
window.attachEvent('onload',init); window.attachEvent('onload',init); function init(){ alert('Lee'); }
window.attachEvent('onload',function(){ var box=document.getElementById('box'); box.attachEvent('onclick',function(){ //alert(this===box); alert(this===window); //true }); });
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); }
Dans la liaison traditionnelle, IE ne peut pas accepter les objets événement via le passage de paramètres comme le W3C, mais cela peut être fait en utilisant 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 }); });
Compatibilité entre navigateurs
Événements multi-navigateurs
function addEvent(obj,type,fn){ if(obj.addEventListener){ obj.addEventListener(type,fn,false); }else if(obj.attachEvent){ obj.attachEvent('on'+type,fn); } }
Événement de suppression multi-navigateurs
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加载方面的事件。