html中与JAVAscript交互是通过事件驱动来实现的,例如鼠标点击事件、页面的滚动事件onscroll等等,可以向文档或者文档中的元素添加事件侦听器来预订事件。想要知道这些事件是在什么时候进行调用的,就需要了解一下“事件流”的概念。
事件流描述的就是从页面中接收事件的顺序。而早期的IE和Netscape提出了完全相反的事件流概念,IE事件流是事件冒泡,而Netscape的事件流就是事件捕获。
即从下至上,从目标触发的元素逐级向上传播,直到window对象。
即从上至下,从document逐级向下传播到目标元素。
后来ECMAScript在DOM2中对事件流进行了进一步规范,基本上就是上述二者的结合。
DOM2级事件规定的事件流包括三个阶段:
注意:warning::先捕获后冒泡,但是在目标节点上谁写在前面谁先执行。但是在目标元素上不区分冒泡还是捕获,按绑定的顺序来执行。
分为四个级别
DOM0:不是W3C规范。
DOM1:开始是W3C规范。专注于HTML文档和XML文档。
DOM2:对DOM1增加了 样式表对象模型
DOM3:对DOM2增加了 内容模型 (DTD 、Schemas) 和 文档验证 。
DOM0级事件具有极好的跨浏览器优势,会以最快的速度绑定。绑定方式有如下两种
将函数名直接作为html标签中属性的属性值。
<div onclick="btnClick()">按钮</div>
<script>
function btnClick(){
console.log("hello");
}
</script>
通过在JS中选中某个节点,然后给节点添加onclick属性
<div id="btn">按钮</div>
<script>
var btn = document.getElementById("btn");
btn.onclick = function(){
console.log("点击");
}
</script>
其中DOM1级事件处理标准中并没有定义事件相关的内容,所以没有所谓的DOM1事件处理
DOM2级定义了两个事件处理程序。(观察者模式)
函数均有3个参数, 第一个参数是要处理的事件名 第二个参数是作为事件处理程序的函数 第三个参数是一个boolean值,默认false表示使用冒泡机制,true表示捕获机制。
<div id="btn">按钮</div>
<script>
var btn=document.getElementById("btn");
btn.addEventListener("click",hello,false);
btn.addEventListener("click",helloagain,false);
function hello(){
console.log("hello");
}
function helloagain(){
console.log("hello again");
}
</script>
// 点击后结果: // hello// hello again
注意:warning:
如果定义了一模一样的监听方法时,是会发生覆盖的。
<div id="btn">点击</div>
<script>
var btn=document.getElementById("btn");
btn.addEventListener("click",hello,false);
btn.addEventListener("click",hello,false);
function hello(){
console.log("hello");
}
</script>
// 点击后结果: // hello
对DOM2增加了 内容模型 (DTD 、Schemas) 和 文档验证 。定义了一些新的事件,比如键盘事件,还可以自定义事件。
自定义事件不是由DOM原生触发的,它的目的是让开发人员创建自己的事件。要创建的自定义事件可以由createEvent("CustomEvent"); 返回的对象有一个initCustomEvent()方法接收如下四个参数。
可以像分配其他事件一样在DOM中分派创建的自定义事件对象。如:
var div = document.getElementById("myDiv");
EventUtil.addEventHandler(div,"myEvent", function () {
alert("div 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!");
div.dispatchEvent(e);}
这个例子中创建了一个冒泡事件“myEvent”。而event.detail的值被设置成了一个简单的字符串,然后在div和document上侦听该事件,因为在initCustomEvent中设置了事件冒泡。所以当div激发该事件时,浏览器会将该事件冒泡到document。
stopPropagation函数
btn.addEventListener('click',function(ev){
ev.stopPropagation(); console.log('阻止冒泡')
}, false)
如果有多个DOM节点需要监听事件的情况下,给每个DOM绑定监听函数,会极大的影响页面的性能,因为我们通过事件委托来进行优化,事件委托利用的就是冒泡的原理。
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
<script>
var li_list = document.getElementsByTagName('li')
for(let index = 0;index<li_list.length;index++){
li_list[index].addEventListener('click', function(ev){
console.log(ev.currentTarget.innerHTML)
})
}
</script>
正常情况我们给每一个li都会绑定一个事件,但是如果这时候li是动态渲染的,数据又特别大的时候,每次渲染后(有新增的情况)我们还需要重新来绑定,又繁琐又耗性能;这时候我们可以将绑定事件委托到li的父级元素,即ul。
var ul_dom = document.getElementsByTagName('ul')
ul_dom[0].addEventListener('click', function(ev){
console.log(ev.target.innerHTML)
})
target和currentTarget区别:
参考自
JS高级程序设计
https://zhuanlan.zhihu.com/p/114276880
https://www.jianshu.com/p/7f5f4c74dde8
https://www.jianshu.com/p/5d2905584a2f
https://www.jianshu.com/p/394e31cc8e7f
本文作者:一只菜鸟攻城狮啊
原文地址:https://www.cnblogs.com/suihang/p/13599887.html