Home > Web Front-end > JS Tutorial > Detailed explanation of DOM event flow in js

Detailed explanation of DOM event flow in js

小云云
Release: 2018-03-20 17:46:30
Original
1830 people have browsed it

An event is some action performed by the user or the browser itself. Such as click, load, mouseover. Event flow describes the order in which events are received from the page, and can also be understood as the order in which events are propagated in the page. Event handler A function that responds to an event is called an event handler (or event listener).

DOM0 level event handler

The following example shows two methods for dom0 to bind events and how to unbind events. When executing the code, we find that if two events are bound to the same element at the same time If so, the event bound later will overwrite the event bound earlier.

<!DOCTYPE html>
<html>
<head>
   <meta charset="UTF-8">
   <title>Title</title>
</head>
<body>
       <button type="button" id="btn" onclick="alert(&#39;btn1&#39;)">点击按钮</button>
</body>
<script>    var btn=document.getElementById("btn");    //绑定事件    btn.onclick=function(){        alert("btn");
   };    //事件解绑    btn.onclick=null;
</script>
</html>
Copy after login

dom2 level event handler

<!DOCTYPE html>
<html>
<head>
   <meta charset="UTF-8">
   <meta name="viewport"          content="width=device-width, initial-scale=1.0, maximum-scale=1.0,minimum-scale=1.0,user-scalable=0"/>
   <title>Title</title>
</head>
<body>
<button type="button" id="btn" onclick="alert(&#39;btn1&#39;)">点击按钮</button>
</body>
<script>    var btn=document.getElementById("btn");    //绑定事件    btn.addEventListener("click",function(){         alert("btn");
   },false);    //事件解绑   btn.removeEventListener("click",function(){       alert("解绑");
  })
</script>
</html>
Copy after login

Note: The third parameter of the addEventListener() method defaults to false, that is, the program is executed in the form of event bubbling. If it is true, then Execution program in the form of event capture. Limited to non-IE browsers, IE browsers use attachEventListener to bind events. Regarding the binding and unbinding of events in IE and non-IE browsers, I will write an example to show the difference between the two.

var eventUtil = {    //添加事件    addEventHandle:function(element,eventType,fn){        if(element.addEventListener){//非IE            element.addEventListener(eventType,fn,false);
       }else if(element.attachEvent){//IE            element.attachEvent(&#39;on&#39;+eventType,fn);//这里拼接上&#39;on&#39;,调运的时候不要加on,使用click等。        }else{//不支持DOM2级,使用DOM0级方式            element[&#39;on&#39;+eventType] = fn;//这里使用[]方式实现对象的属性添加,相当于.的作用        }
   },    //删除事件    removeEventHandle:function(element,eventType,fn){        if(element.removeEventListener){//非IE,不带&#39;on&#39;            element.removeEventListener(eventType,fn,false);
       }else if(element.detachEvent){//IE,带&#39;on&#39;            element.detachEvent(&#39;on&#39;+eventType,fn);
       }else{//不支持DOM2级,使用DOM0级方式            element[&#39;on&#39;+eventType] = fn;
       }
   },    //获取事件对象    getEvent:function(event){        return event?event:window.event;
   },    //获取事件类型    getType:function(event){        return event.type;
   },    //获取执行事件的目标元素    getTarget:function(event){        return event.target||event.srcElement;
   },    //禁用默认行为    preventDefault:function(event){        if(event.preventDefault){            event.preventDefault();//非IE        }else{            event.returnValue = false;//针对IE        }

   },    //阻止传播冒泡    stopPropagation:function(event){        if(event.stopPrapagation){            event.stopPropagation();//非IE        }else{            event.cancelBubble = true;//针对IE        }
   }
}
Copy after login

dom3事件处理程序

DOM浏览器中可能发生的事件有很多种,不同事件类型具有不同的信息,DOM3级事件规定了一下几种事件:
UI事件,当用户与页面上的元素交互时触发;
焦点事件,当元素获得或者失去焦点时触发;
鼠标事件,当用户通过鼠标在页面上执行操作时触发;
滚轮事件,当使用鼠标滚轮(或类似设备)时触发;
文本事件,当在文档中,输入文本时触发;
键盘事件,当用户通过键盘在页面上执行操作时触发;
合成事件,当为IME(Input Method Editor,输入法编辑器)输入字符时触发;
变动事件,当底层Dom结构发生变化时触发;
DOM3级事件模块在DOM2级事件的基础上重新定义了这些事件,也添加了一些新事件。包括IE9在内的主流浏览器都支持DOM2级事件,IE9也支持DOM3级事件。
DOM中的事件模拟(自定义事件):
DOM3级还定义了自定义事件,自定义事件不是由DOM原生触发的,它的目的是让开发人员创建自己的事件。要创建的自定义事件可以由createEvent("CustomEvent");
返回的对象有一个initCustomEvent()方法接收如下四个参数。
1)type:字符串,触发的事件类型,自定义。例如 “keyDown”,“selectedChange”;
2)bubble(布尔值):标示事件是否应该冒泡;
3)cancelable(布尔值):标示事件是否可以取消;
4)detail(对象):任意值,保存在event对象的detail属性中;
可以像分配其他事件一样在DOM中分派创建的自定义事件对象。如:

   
var  p = document.getElementById("myp");
EventUtil.addEventHandler(p,"myEvent", function () {
alert("p myEvent!");
});
EventUtil.addEventHandler(document,"myEvent",function(){
alert("document myEvent!");
});
if(document.implementation.hasFeature("CustomEvents","3.0")){
var e = document.createEvent("CustomEvent");
e.initCustomEvent("myEvent",true,false,"hello world!");
p.dispatchEvent(e);
}
Copy after login

这个例子中创建了一个冒泡事件“myEvent”。而event.detail的值被设置成了一个简单的字符串,然后在p和document上侦听该事件,因为在initCustomEvent中设置了事件冒泡。所以当p激发该事件时,浏览器会将该事件冒泡到document。
IE中的事件模拟(IE8及之前版本中):
与DOM中事件模拟的思路类似,先创建event对象,再为其指定相应信息,然后再使用该对象来触发事件。当然IE在实现以下每个步骤都不太一样。
例如:

var btn = document.getElementById("myBtn");
//创建事件对象,不接受任何参数,结果会返回一个通用的event对象,你必须为该event对象指定所有必要的信息。
var event  = document.createEventObject();
//初始化事件对象
event.screenX = 100;
event.screenY = 0;
event.clientX = 0;
event.clientY =0;
event.ctrlKey = false;
event.altKey = false;
event.shiftKey = false;
event.button = 0;

//触发事件
btn.fireEvent("onclick",event);
Copy after login

事件流的分类

  • 事件冒泡流:IE的事件流叫事件冒泡,即事件开始时由最具体的元素(文档中嵌套层次最深的节点)接收,然后逐级向上传播到较为不具体的节点

  • 事件捕获流:Netscape团队提出的另一种事件流叫事件捕获,事件捕获的思想是不太具体的节点应该更早接收到事件,而最具体的节点应该最后接收到事件

  • dom事件流:DOM2级事件”规定的事件流包括三个阶段:事件捕获阶段==>处于目标阶段==>事件冒泡阶段。首先发生的是事件捕获阶段,为截获事件提供了机会。然后是实际的目标接收事件。最后一个阶段是冒泡阶段。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
       <p id="node1">
           <p id="node2">
               <p id="node3">
                   <p id="node4">click me</p>
               </p>
           </p>
       </p>
</body>
<script>    var node1=document.getElementById("node1");    var node2=document.getElementById("node2");    var node3=document.getElementById("node3");    var node4=document.getElementById("node4");    node1.addEventListener("click",function(){        alert("node1");
    },false);    node2.addEventListener("click",function(){        alert("node2");
    },false);    node3.addEventListener("click",function(){        alert("node3");
    },false);    node4.addEventListener("click",function(){        alert("node4");
    },false);
</script>
</html>
Copy after login

以上代码分别给node1-node4个节点绑定事件,且采用事件冒泡的形式执行,从而分别会弹出node4->node3->node3->node1

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
       <p id="node1">
           <p id="node2">
               <p id="node3">
                   <p id="node4">click me</p>
               </p>
           </p>
       </p>
</body>
<script>    var node1=document.getElementById("node1");    var node2=document.getElementById("node2");    var node3=document.getElementById("node3");    var node4=document.getElementById("node4");    node1.addEventListener("click",function(){        alert("node1");
    },true);    node2.addEventListener("click",function(){        alert("node2");
    },true);    node3.addEventListener("click",function(){        alert("node3");
    },true);    node4.addEventListener("click",function(){        alert("node4");
    },true);
</script>
</html>
Copy after login

以上代码分别给node1-node4个节点绑定事件,且采用事件捕获的形式执行,从而分别会弹出node1->node2->node3->node4.

那如果给同一元素同事绑定两个事件,一个采用冒泡一个采用捕获则程序会按照dom流的形式来执行程序即"先捕获后冒泡"

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
       <p id="node1">
           <p id="node2">
               <p id="node3">
                   <p id="node4">click me</p>
               </p>
           </p>
       </p>
</body>
<script>    var node1=document.getElementById("node1");    var node2=document.getElementById("node2");    var node3=document.getElementById("node3");    var node4=document.getElementById("node4");    node1.addEventListener("click",function(){        alert("node1");
    },false);    node2.addEventListener("click",function(){        alert("node2");
    },false);    node3.addEventListener("click",function(){        alert("node3");
    },false);    node4.addEventListener("click",function(){        alert("node4");
    },false);    
    
    node1.addEventListener("click",function(){        alert("node1");
    },true);    node2.addEventListener("click",function(){        alert("node2");
    },true);    node3.addEventListener("click",function(){        alert("node3");
    },true);    node4.addEventListener("click",function(){        alert("node4");
    },true);
    
    
</script>
</html>
Copy after login

程序执行顺序:node1->node2->node3->node4->node4->node3->node2->node1.

事件代理

含义:事件代理即事件委托,就是利用事件冒泡只制定一个事件处理程序就可以管理某一类型的所有事件

为什么:一般来说,dom需要有事件处理程序,我们都会直接给它设事件处理程序就好了,那如果是很多的dom需要添加事件处理呢?比如我们有100个li,每个li都有相同的click点击事件,可能我们会用for循环的方法,来遍历所有的li,然后给它们添加事件,那这么做会存在什么影响呢?在JavaScript中,添加到页面上的事件处理程序数量将直接关系到页面的整体运行性能,因为需要不断的与dom节点进行交互,访问dom的次数越多,引起浏览器重绘与重排的次数也就越多,就会延长整个页面的交互就绪时间,这就是为什么性能优化的主要思想之一就是减少DOM操作的原因;如果要用事件委托,就会将所有的操作放到js程序里面,与dom的操作就只需要交互一次,这样就能大大的减少与dom的交互次数,提高性能;

每个函数都是一个对象,是对象就会占用内存,对象越多,内存占用率就越大,自然性能就越差了(内存不够用,是硬伤,哈哈),比如上面的100个li,就要占用100个内存空间,如果是1000个,10000个呢,那只能说呵呵了,如果用事件委托,那么我们就可以只对它的父级(如果只有一个父级)这一个对象进行操作,这样我们就需要一个内存空间就够了,是不是省了很多,自然性能就会更好。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<ul id="ul1">
    <li>111</li>
    <li>222</li>
    <li>333</li>
    <li>444</li>
</ul>
<script>    //无事件代理    window.onload = function(){        var oUl = document.getElementById("ul1");        var aLi = oUl.getElementsByTagName(&#39;li&#39;);        for(var i=0;i<aLi.length;i++){            aLi[i].onclick = function(){                alert(123);
            }
        }
    };    //事件代理    window.onload = function(){        var oUl = document.getElementById("ul1");        oUl.onclick = function(ev){            var ev = ev || window.event;            var target = ev.target || ev.srcElement;            if(target.nodeName.toLowerCase() == &#39;li&#39;){                alert(123);                alert(target.innerHTML);
            }
        }
    }
</script>
</body>
</html>
Copy after login

相关推荐:

js中DOM事件绑定详解

JS中DOM如何操作

js中DOM知识点分享

The above is the detailed content of Detailed explanation of DOM event flow in js. For more information, please follow other related articles on the PHP Chinese website!

source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template