Dans le processus de développement front-end, nous rencontrons souvent le problème de l'ajout d'événements aux éléments de la page. Il existe de nombreuses méthodes js pour ajouter des événements. Certaines sont directement ajoutées à la structure de la page et certaines utilisent des méthodes de surveillance des événements js. . En raison des différents navigateurs, les serveurs disposent de mécanismes différents pour la diffusion d'événements et la surveillance des événements. Le navigateur LE n'a que la diffusion d'événements et aucun mécanisme de surveillance des événements. Le problème de compatibilité pour la surveillance des événements est le plus gros problème :
.1. Écrivez les méthodes d'événement directement sur la structure de la page
function eventfun(){ //console.log(this); } <input type="button" onclick="eventfun()" value="button" />//这里涉及到一个this作用域的问题,eventfun再这里是一个全局函数, 对象是[object Window],this指向的是window.
Pour résoudre le problème de cette portée, vous pouvez utiliser la méthode d'ajout de variables d'événement à la fonction globale et transmettre cet objet en tant que paramètre à la fonction à l'intérieur de la structure de la page
<input type="button" onclick="eventfun2(this)" value="button2" /> function eventfun2(eve){//在这里把事件对象作为参数传递到全局方法里 eve.name="alex"; window.name="robin"; console.log(this);//[object Window] console.log(eve);// [object HTMLInputElement] console.log(this.name);// robin console.log(eve.name);// alexvar self=eve; console.log(this.name);//robin console.log(self.name);//alex alert(window.name); alert(self.name); }
2. L'utilisation de la méthode d'attribution de valeurs aux attributs d'un événement est une méthode de liaison d'événements. Cependant, la limitation de cette méthode est qu'elle ne peut lier qu'une seule méthode à l'événement. Si plusieurs méthodes sont liées, la suivante. méthode sera utilisée. Sous réserve de
HTMLElementobject.onclick = fucntion(){//En utilisant cette méthode d'attribution de valeurs aux attributs d'événement, le pointeur de ceci pointera vers l'objet fenêtre, pas l'objet événement, cette méthode est donc une référence
//js code fun1(); fun2(); fun3(); console.log(this);//window.object } function dosomething(){ //js code } HTMLElementobject.onclick = dosomething;//使用这种为事件对象属性赋值的形式,this指针指向事件执行对象 console.log(this);//htmlElementObject
3. Propagation d'événements - bouillonnement et capture
La norme d'événements DOM définit deux flux d'événements très différents et pouvant avoir un impact considérable sur votre application. Les deux flux d'événements capturent et bouillonnent. Comme de nombreuses technologies Web, Netscape et Microsoft les ont chacune mises en œuvre différemment avant de devenir des standards. Netscape a choisi d'implémenter le flux d'événements de capture, et Microsoft a implémenté le flux d'événements bouillonnants. Heureusement, le W3C a décidé d'utiliser une combinaison de ces deux méthodes, et la plupart des nouveaux navigateurs suivent les deux méthodes de streaming d'événements.
Par défaut, les événements utilisent le flux d'événements bouillonnants et n'utilisent pas le flux d'événements de capture. Cependant, dans Firefox et Safari, vous pouvez spécifier explicitement d'utiliser le flux d'événements de capture en transmettant le paramètre useCapture lors de l'enregistrement de l'événement et en définissant ce paramètre sur true.
Flux d'événements bouillonnants
Lorsqu'un événement est déclenché sur un certain élément du DOM, tel que l'utilisateur cliquant avec la souris sur le nœud du nom du client, l'événement suivra les nœuds parents dont le nœud hérite et parcourra toute la hiérarchie des nœuds DOM jusqu'à ce qu'il rencontre le nœud qui y est attaché. Le nœud du gestionnaire de type d'événement. À ce stade, l'événement est un événement onclick. La diffusion d'événements peut être interrompue à tout moment pendant le processus de diffusion. Dans les navigateurs conformes à la norme W3C, vous pouvez appeler la méthode stopPropagation() sur l'objet événement. Dans Internet Explorer, vous pouvez définir la propriété CancelBubble de l'objet événement. vrai. . Si vous n'arrêtez pas la propagation de l'événement, celui-ci continuera à circuler dans le DOM jusqu'à ce qu'il atteigne la racine du document.
Capturer le flux d'événements
Le traitement des événements commencera à la racine de la hiérarchie DOM, plutôt qu'à partir de l'élément cible qui a déclenché l'événement. L'événement est transmis depuis tous les éléments ancêtres de l'élément cible dans l'ordre. Dans ce processus, l'événement sera capturé par chaque élément hérité de la racine du document vers l'élément cible de l'événement. Si l'écouteur d'événement définit l'attribut useCapture sur true lors de son enregistrement, ils peuvent alors être distribués à n'importe quel élément pendant cette période. élément pour gérer l'événement ; sinon, l'événement est ensuite transmis à l'élément suivant sur le chemin d'accès à l'élément dérivé, jusqu'à l'élément cible. Une fois que l'événement a atteint l'élément cible, il bouillonnera ensuite à travers les nœuds DOM.
Méthodes modernes de liaison d'événements
Comme indiqué dans la leçon précédente, l'utilisation de la liaison d'événements traditionnelle présente de nombreux inconvénients, tels que l'impossibilité d'enregistrer plusieurs gestionnaires d'événements pour le même événement sur un objet. Les navigateurs et le W3C n'ont pas pris cela en considération, c'est pourquoi les navigateurs modernes ont leurs propres méthodes pour lier les événements.
W3C DOM
obj.addEventListener(evtype,fn,useCapture) ——Méthode fournie par le W3C pour ajouter une fonction de gestion des événements. obj est l'objet pour ajouter l'événement, evtype est le type d'événement sans préfixe on, fn est la fonction de traitement d'événement, si useCapture est vrai, la fonction de traitement d'événement est exécutée en phase de capture, sinon elle est exécutée en phase de bouillonnement
obj.removeEventListener(evtype,fn,useCapture)——Méthode fournie par le W3C pour supprimer la fonction de gestionnaire d'événements
Méthode Microsoft IE
obj.attachEvent(evtype,fn) ——La méthode fournie par IE pour ajouter une fonction de traitement d'événements. obj est l'objet pour ajouter l'événement, evtype est le type d'événement, avec le préfixe on, fn est la fonction de traitement d'événement, IE ne prend pas en charge la capture d'événement
obj.detachEvent(evtype,fn,) ——La méthode fournie par IE pour supprimer les fonctions de traitement d'événements evtype contient le préfixe on
Méthodes pour intégrer les deux
function addEvent(obj,evtype,fn,useCapture) { if (obj.addEventListener) { obj.addEventListener(evtype,fn,useCapture); } else { obj.attachEvent("on"+evtype,fn);//IE不支持事件捕获 } else { obj["on"+evtype]=fn;//事实上这种情况不会存在 } } function delEvent(obj,evtype,fn,useCapture) { if (obj.removeEventListener) { obj.removeEventListener(evtype,fn,useCapture); } else { obj.detachEvent("on"+evtype,fn); } else { obj["on"+evtype]=null; } }
Il y a un problème avec la méthode attach d'IE lors de l'utilisation de attachEvent, dans la fonction de traitement des événements, cela pointe vers window, pas obj ! Bien sûr, il existe une solution à cela !
Mais la méthode attachEvent d'IE a un autre problème. La même fonction peut être enregistrée plusieurs fois sur le même objet et le même événement. La solution : abandonnez la méthode attachEvent d'IE ! La méthode attachEvent sous IE ne prend pas en charge la capture et n'est pas très différente de l'enregistrement d'événements traditionnel (sauf qu'elle peut lier plusieurs fonctions de traitement d'événements), et la méthode attachEvent d'IE a un problème de fuite de mémoire !
addEvent,delEvent version moderne
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>js事件监听</title> <style> table td{font:12px; border-bottom:1px solid #efefef;} </style> </head> <body> <div id="outEle" style="padding:10px; border:1px solid #b2b2b2; background:#efefef;"> <input type="button" onclick="eventfun()" id="button" value="button" /><br /> <input type="button" onclick="eventfun2(this);" id="button2" value="button2" /><br /> <input type="button" id="button3" value="button3" /><br /> <input type="button" id="button4" value="button4" /><br /> <table id="htmlEleTable" width="100%" border="0" style="border:1px solid #b2b2b2; background:#fff;"> <tr id="1111"><td>111111111111111111111111111111</td></tr> <tr id="22222"><td>222222222222222222222222222222</td></tr> <tr id="33333"><td>333333333333333333333333333333</td></tr> <tr id="4444"><td>444444444444444444444444444444</td></tr> <tr id="55555"><td>555555555555555555555555555555</td></tr> </table> </div> <script language="javascript" type="text/javascript"> function eventfun(){//1.直接把js方法写在页面结构上 console.log(this);//这里涉及到一个this作用域的问题,eventfun再这里是一个全局函数, 对象是window,this指向的是window alert(this); } function eventfun2(eve){//在这里把事件对象作为参数传递到全局方法里 eve.name="alex";// window.name="robin"; console.log(this);//[object Window] console.log(eve);// [object HTMLInputElement] console.log(this.name);// robin console.log(eve.name);// alex var self=eve; console.log(this.name);//robin console.log(self.name);//alex alert(window.name); alert(self.name); } function eventfun3(){//1.直接把js方法写在页面结构上 console.log(this);//这里涉及到一个this作用域的问题,eventfun再这里是一个全局函数, 对象是window,this指向的是window console.log(this.id); alert(this); alert(this.id); //var outEleObj = EventUtil.$("outEle"); //removeEvent(outEleObj,"click",eventfun3); } /* var EventUtil = {}; EventUtil.$ = function(id){ return document.getElementById(id); } EventUtil.openmes = eventfun3; EventUtil.addEventHandle = function(eventTarget,eventtype,eventHandle){//定义事件监听的对象元素,事件类型,事件函数 if(eventTarget.attachEvent){ eventTarget.attachEvent("on"+eventtype,eventHandle); }else if(eventTarget.addEventListener){ eventTarget.addEventListener(eventtype,eventHandle,false) }else{ eventTarget["on" + eventtype] = null; } }; EventUtil.deleEventHandle = function(eventTarget,eventtype,eventHandle){//定义事件监听的对象元素,事件类型,事件函数 if(eventTarget.detachEvent){ alert("on"+eventtype); alert("on"+eventHandle); eventTarget.detachEvent("on"+eventtype,eventHandle); }else if(eventTarget.removeEventListener){ eventTarget.removeEventListener(eventtype,eventHandle,false) }else{ eventTarget["on" + eventtype] = null; } };*/ var EventUtil={ $:function(id){ return document.getElementById(id); }, but4fun:function(){ console.log(this); this.addEventHandle(); }, eventfun3:function (){ console.log(this); alert(this); delEvent(obj,evtype,fn,useCapture); } } /***使用addEventListener,attachEvent进行dom事件的监听 function addEvent(obj,evtype,fn,useCapture){ if (obj.addEventListener) { obj.addEventListener(evtype,fn,useCapture); }else if(obj.attachEvent){ obj.attachEvent("on"+evtype,function () { fn.call(obj); }); }else { obj["on"+evtype]=fn;//事实上这种情况不会存在 } } function delEvent(obj,evtype,fn,useCapture) { if (obj.removeEventListener) { obj.removeEventListener(evtype,fn,useCapture); } else if(obj.detachEvent){ obj.detachEvent("on"+evtype,fn); } else { obj["on"+evtype]=null; } } function addEvent(obj,evtype,fn,useCapture) { if (obj.addEventListener) {//优先考虑W3C事件注册方案 obj.addEventListener(evtype,fn,!!useCapture); } else {//当不支持addEventListener时(IE),由于IE同时也不支持捕获,所以不如使用传统事件绑定 if (!fn.__EventID) {fn.__EventID = addEvent.__EventHandlesCounter++;} //为每个事件处理函数分配一个唯一的ID if (!obj.__EventHandles) {obj.__EventHandles={};} //__EventHandles属性用来保存所有事件处理函数的引用 //按事件类型分类 if (!obj.__EventHandles[evtype]) {//第一次注册某事件时 obj.__EventHandles[evtype]={}; if (obj["on"+evtype]) {//以前曾用传统方式注册过事件处理函数 (obj.__EventHandles[evtype][0]=obj["on"+evtype]).__EventID=0;//添加到预留的0位 //并且给原来的事件处理函数增加一个ID } obj["on"+evtype]=addEvent.execEventHandles; //当事件发生时,execEventHandles遍历表obj.__EventHandles[evtype]并执行其中的函数 } } } addEvent.__EventHandlesCounter=1;//计数器,0位预留它用 addEvent.execEventHandles = function (evt) {//遍历所有的事件处理函数并执行 if (!this.__EventHandles) {return true;} evt = evt || window.event; var fns = this.__EventHandles[evt.type]; for (var i in fns) { fns[i].call(this); } }; /* function delEvent(obj,evtype,fn,useCapture) { if (obj.removeEventListener) {//先使用W3C的方法移除事件处理函数 obj.removeEventListener(evtype,fn,!!useCapture); } else { if (obj.__EventHandles) { var fns = obj.__EventHandles[evtype]; if (fns) {delete fns[fn.__EventID];} } } } function fixEvent(evt) {//fixEvent函数不是单独执行的,它必须有一个事件对象参数,而且只有事件发生时它才被执行!最好的方法是把它整合到addEvent函数的execEventHandles里面 if (!evt.target) { evt.target = evt.srcElement; evt.preventDefault = fixEvent.preventDefault; evt.stopPropagation = fixEvent.stopPropagation; if (evt.type == "mouseover") { evt.relatedTarget = evt.fromElement; } else if (evt.type =="mouseout") { evt.relatedTarget = evt.toElement; } evt.charCode = (evt.type=="keypress")?evt.keyCode:0; evt.eventPhase = 2;//IE仅工作在冒泡阶段 evt.timeStamp = (new Date()).getTime();//仅将其设为当前时间 } return evt; } fixEvent.preventDefault =function () { this.returnValue = false;//这里的this指向了某个事件对象,而不是fixEvent }; fixEvent.stopPropagation =function () { this.cancelBubble = true; };*/ //console.log(EventUtil.$("button3"));//返回EventUtil函数的对象属性 //EventUtil.$("button3").onclick= eventfun;//2.使用为对象事件属性赋值的方法来实现事件的监听 //EventUtil.$("button3").onclick= eventfun2;//为事件属性添加多个方法时,为后者 //EventUtil.$("button3").onclick= eventfun;//事件捕获是从事件对象逐层外父级检察一直到window对象 var EventUtil =function(){ function getByid(id){ return document.getElementById(id); }; // written by Dean Edwards, 2005 // with input from Tino Zijdel, Matthias Miller, Diego Perini // http://dean.edwards.name/weblog/2005/10/add-event/ function addEvent(element, type, handler) { if (element.addEventListener) { element.addEventListener(type, handler, false); } else { // assign each event handler a unique ID if (!handler.$$guid) handler.$$guid = addEvent.guid++; // create a hash table of event types for the element if (!element.events) element.events = {}; // create a hash table of event handlers for each element/event pair var handlers = element.events[type]; if (!handlers) { handlers = element.events[type] = {}; // store the existing event handler (if there is one) if (element["on" + type]) { handlers[0] = element["on" + type]; } } // store the event handler in the hash table handlers[handler.$$guid] = handler; // assign a global event handler to do all the work element["on" + type] = handleEvent; } }; // a counter used to create unique IDs addEvent.guid = 1; function removeEvent(element, type, handler) { if (element.removeEventListener) { element.removeEventListener(type, handler, false); } else { // delete the event handler from the hash table if (element.events && element.events[type]) { delete element.events[type][handler.$$guid]; } } }; function handleEvent(event) { var returnValue = true; // grab the event object (IE uses a global event object) event = event || fixEvent(((this.ownerDocument || this.document || this).parentWindow || window).event); // get a reference to the hash table of event handlers var handlers = this.events[event.type]; // execute each event handler for (var i in handlers) { this.$$handleEvent = handlers[i]; if (this.$$handleEvent(event) === false) { returnValue = false; } } return returnValue; }; function fixEvent(event) { // add W3C standard event methods event.preventDefault = fixEvent.preventDefault; event.stopPropagation = fixEvent.stopPropagation; return event; }; fixEvent.preventDefault = function() { this.returnValue = false; }; fixEvent.stopPropagation = function() { this.cancelBubble = true; }; function tableAddEvent(){ }; return{ add:addEvent, remove:removeEvent, $:getByid } }(); var outEleObj = EventUtil.$("outEle"); //addEvent.apply(EventUtil,[outEleObj,"click",eventfun3]); //EventUtil.add(outEleObj,"click",eventfun3); var inputObj = EventUtil.$("button4"); var tableEle = EventUtil.$("htmlEleTable"); var tabTrEle = tableEle.getElementsByTagName("tr"); EventUtil.add(tableEle,"click",eventfun3); for (i=0; i<tabTrEle.length; i++){ EventUtil.add(tabTrEle[i],"click",eventfun3); } EventUtil.remove(tableEle,"click",eventfun3);//事件冒删除方法 EventUtil.add(tableEle,"click",eventfun3);//事件冒泡添加方法 //EventUtil.add(inputObj,"click",eventfun3); //EventUtil.remove(outEleObj,"click",eventfun3); //console.log(addEvent); //addEvent(inputObj,"click",eventfun3,true); //delEvent(outEleObj,"click",eventfun3,false); </script> </body> </html>