文章目录
DOM0级事件和DOM2级事件
事件就是用户或浏览器自身执行的某种操作,如click、load、mouseover等,都是事件的名字,而响应某个事件的函数就被称为事件处理程序。
事件过程
当用户操作浏览器的时候,浏览器一直监听者用户的操作,会触发若干个事件,同时检测事件是否有赋值某个事件函数,如果未赋值为null , 如果某个事件上有事件函数,那么就被执行;
btn.onclick // ==null == 未赋值
btn.haha // == undefined == 自定义的
一、0级DOM
0级DOM分为两种
1、在标签内写onclick事件
2、在JS写οnclick=function(){}函数
- 解除事件将某个元素的事件赋值为null
ele.事件 = null
// 1、行内
<button id="btn" onclick="alert(1)">按钮</button>
// 2、元素,on事件名 = 函数
document.getElementById("btn")..onclick = function(){
alert(1);
}
0级DOM事件的特点
- 1、DOM0级事件只能触发事件冒泡阶段不能触发事件捕获阶段。
box2.onclick = function(){
alert("我是box2");
}
box3.onclick = function(){
alert("我是box3");
}
不管怎么改变事件的绑定顺序,不影响弹出框。box2–>box3,因为DOM0只能触发事件冒泡不能触发事件捕获。
2、同一元素绑定相同的事件,后面的会覆盖前面的。
点击btn 只会弹出2,因为on**方法相当于给元素添加属性。后面写的会覆盖先写的。
///1、覆盖事件演示
btn.onclick = function(){
alert('hello');
}
btn.onclick = function(){
alert('hello,我是真的');
btn.onclick = null; // 只弹一次
}
//此时只会弹出‘hello,我是真的’,因为下边把上边的覆盖了;
// 2、如果需要添加多个事件,那么可以通过一遍这种形式操作
btn.onclick = function(){
fn();
fn2();
};
function fn(){
alert(1)
};
function fn2(){
alert(2)
};
3、this指的是事件流传播到这个元素,就是元素本身
4、DOM0捕获不到捕获阶段,只有冒泡阶段.
二、DOM2级事件处理
监听方法
绑定事件的方法
ele.addEventListener()
解除事件的方法
ele.removeEventListener()
有三个参数
- 第一个参数,事件名(如click、mouseover等);
- 第二个参数,事件函数;
- 第三个参数,如果是true则表示在捕获阶段调用,为false表示在冒泡
ele.addEventListener(‘不带on的事件名’,函数,是否捕获)
ele.removeEventListener(‘不带on的事件名’,有名函数(和绑定函数一个地址),是否捕获);
//第一种清除方式--- 有效
btn.addEventListener('click', function hh() {
alert(2);
btn.removeEventListener('click', hh);
});
//第二种清除方式 ---无效,虽然执行内容一样,但是地址改变了,非同一地址
let cc = c.bind(this)
btn.addEventListener('click',c);
function c(){
alert(1);
btn.removeEventListener('click',cc);
}
请注意此时DOM2清除的必须是有名函数,并且第一样;
DOM2的特点
1、同一个元素绑定相同的事件,后面的不会覆盖前面的。
因为DOM2级事件绑定不是给元素添加属性是直接添加的事件。等同于给一个元素绑定了多个事件。
2、在DOM2级事件处理中通过addEventListener()添加的匿名函数无法移除,只能清除有名函数;
3、2级DOM包含3个事件:事件捕获阶段、处于目标阶段和事件冒泡阶段;
事件模型(事件流)
事件模型预告
只有2级DOM包含3个事件:事件捕获阶段、处于目标阶段和事件冒泡阶段;
在点击按钮的时候,不但弹出了"我是box" 也弹出我是 “我是btn” ,这是因为元素的事件基本上都遵循事件模型机制。
<body>
<div id="box">我是box
<button id="btn">我是按钮</button>
</div>
<script>
box.onclick = function(){
alert('我是box');
}
btn.onclick = function(){
alert('我是btn');
}
</script>
点击a后capturing(捕捉)阶段事件传播会 从 document-> div ->button
,然后发生在button,最后bubbling(冒泡)阶段事件传播会从button->div ->document
。
事件模型
从捕获阶段 到 目标阶段 再到 冒泡阶段 的过程称为事件流。
先执行捕获再执行冒泡。
1.冒泡阶段(常用)
- 从目标点由下而上 直到window ,叫做冒泡阶段 。
- 事件冒泡可以形象地比喻为把一颗石头投入水中,泡泡会一直从水底冒出水面。也就是说,事件会从最内层的元素开始发生,一直向上传播,直到document对象。
- 在这个过程中,如果上级和下级同理有祖先关系,绑定同一事件函数 先触发目标 再触发目标的上级;
2.捕获阶段
- 从window 到 目标点的阶段 ,叫捕获阶段
- 在捕获的过程中,如果上级和下级(祖先级关系)绑定同一事件函数,那么先触发上级的在触发下级的;
ps : 如果事件绑定的是目标元素,那么是按照绑定事件函数的先后顺序来依次执行(跟捕获冒泡没关系)
小例子
做做小练习,看看他们的执行顺序,看看自己是否真的理解 事件模型;
function fn(){alert('btn1');}
btn.addEventListener('click',fn,true);
btn.addEventListener('click',function(){alert(1);},true);
btn.addEventListener('click',function(){alert(2);},true);
box1.addEventListener('click',function(){alert('red');});
btn.addEventListener('click',fn,true);
box3.addEventListener('click',function(){alert('yellow');},true);
box2.addEventListener('click',function(){alert('blue');},true);
box2.addEventListener('click',function(){ alert('green');});
btn.addEventListener('click',function(){alert('btn捕获');},true);
btn.addEventListener('click',fn,false);
btn.addEventListener('click',function(){alert('btn冒泡');});
btn.addEventListener('click',function(){alert('btn冒泡2');});
冒泡的好处— 事件委托
- 如果一个父节点内含有多个子节点,并且每个子节点都存在同一事件类型(如onclick)。我们可以为其父代设置一个事件处理器(onclick),来避免为其每个子代设置一个事件处理器,降低内存,提高性能。
<body>
<ul id="ul">
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
<script>
//之前的方式 --- 需要循环,消耗性能
const lis = document.querySelectorAll('li');
lis.forEach(e => {
e.onclick = function () {
this.style.background = 'green';
}
});
//冒泡--事件委托
ul.onclick = function (ev) {
if (ev.target.tagName === 'LI') {
ev.target.style.background = 'green';
}
}
</script>
// ev.target 目标点(事件源)
// 在嵌套关系中,给上层元素绑定事件,可以通过事件源查到事件触发的对象(元素)
// tagName 查看标签名 注意:大写
冒泡的坏处 — 阻止冒泡
背景:
事件函数中的第一个参数,默认为事件对象。
-
事件对象:当用户触发某个事件的时候,记录用户操作页面的一些细节信息,也就会出现,自己冒泡触发祖先级的同一事件;
event
chrome/IE window中都有一个event
FF中是没有event对象的 *
阻止冒泡: (目的是为了不让自己冒泡触发祖先级的同一事件)
ev.cancelBubble = true;
它不是一个标准,但是所有浏览器都支持;
ev.stopPropagation();
它是标准,但是在低版本IE下是不兼容的;
如下:
<body>
<button id="btn">打开</button>
<div id="box"></div>
<script>
let onoff = true;
btn.onclick = function(ev){
if(onoff){
box.style.display = 'block';
btn.innerHTML = '隐藏'
}else{
box.style.display = 'none';
btn.innerHTML = '打开'
}
onoff = !onoff;
ev.cancelBubble = true;
// ev.stopPropagation();
}
document.onclick = function(){
box.style.display = 'none';
onoff = true;
btn.innerHTML = '打开'
}
点击button的时候,也会触发document使box.style.display = ‘none’;
那么我们可以在目标源阻止ev.cancelBubble = true; /ev.stopPropagation();
阻止自己冒泡触发祖先级的同一事件;