DOM事件总结

DOM事件的级别

DOM事件的级别,准确来说,是DOM标准定义的级别。包括:

DOM0的写法:

1
2
3
4
//这种事件绑定的方式,如果绑定多个,则后面的会覆盖掉前面的
element.onclick = function () {
alert('hello');
}

上面的代码是在 js 中的写法;如果要在html中写,写法是:在onclick属性中,加 js 语句。

1
<button onclick="alert('hello');">我是按钮</button>  

DOM2的写法:

1
2
3
4
// 高版本浏览器
element.addEventListener('click', function () {
alert('hello');
}, false);

【重要】上面的第三参数中,true表示事件在捕获阶段触发,false表示事件在冒泡阶段触发(默认)。如果不写,则默认为false。

1
2
3
4
// IE8及以下版本浏览器。IE11和谷歌浏览器等不支持
element.attachEvent('onclick', function () {
alert('hello');
});
  • 参数1:事件名的字符串(注意,有on)
  • 参数2:回调函数:当事件触发时,该函数会被执行

不同:

  • addEventListener()中的this,是绑定事件的对象;如果写箭头函数是window。绑定多个响应函数执行顺序是:先绑定先执行

  • attachEvent()中的thiswindow 。绑定多个响应函数执行顺序是,后绑定先执行

兼容写法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//定义一个函数,用来为指定元素绑定响应函数
/*
* addEventListener()中的this,是绑定事件的对象
* attachEvent()中的this,是window
* 需要统一两个方法this
*/
/*
* 参数:
* element 要绑定事件的对象
* eventStr 事件的字符串(不要on)
* callback 回调函数
*/
function myBind(element , eventStr , callback){
if(element.addEventListener){
//大部分浏览器兼容的方式
element.addEventListener(eventStr , callback , false);
}else{
/*
* this是谁,由调用方式决定
* callback.call(element)
*/
//IE8及以下
element.attachEvent("on"+eventStr , function(){
//在匿名函数 function 中调用回调函数callback
callback.call(element);
});
}
}

补充:call()、apply()、bind() 都是用来重定义 this 这个对象的!bind 返回的是一个新的函数,你必须调用它才会被执行。

DOM3的写法:

1
2
3
element.addEventListener('keyup', function () {
alert('hello');
}, false);

DOM3中,增加了很多事件类型,比如鼠标事件、键盘事件等。

PS:为何事件没有DOM1的写法呢?因为,DOM1标准制定的时候,没有涉及与事件相关的内容。

DOM事件模型、DOM事件流

DOM事件模型

DOM事件模型讲的就是捕获和冒泡

  • 捕获:从上往下。

  • 冒泡:从下(目标元素)往上。

DOM事件流

DOM事件流讲的就是:浏览器在于当前页面做交互时,这个事件是怎么传递到页面上的。

类似于Android里面的事件传递。

完整的事件流,分三个阶段:

  • (1)捕获:从 window 对象传到 目标元素。

  • (2)目标阶段:事件通过捕获,到达目标元素,这个阶段就是目标阶段。

  • (3)冒泡:从目标元素传到 Window 对象。

5KP6Q1.jpg

描述DOM事件捕获的具体流程

捕获的流程

5KPrW9.png

说明:捕获阶段,事件依次传递的顺序是:window –> document –> html–> body –> 父元素、子元素、目标元素。

PS1:第一个接收到事件的对象是 window(有人会说body,有人会说html,这都是错误的)。

PS2:JS中涉及到DOM对象时,有两个对象最常用:window、doucument。它们俩也是最先获取到事件的。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
window.addEventListener("click", function () {
alert("捕获 window");
}, true);

document.addEventListener("click", function () {
alert("捕获 document");
}, true);

document.documentElement.addEventListener("click", function () {
alert("捕获 html");
}, true);

document.body.addEventListener("click", function () {
alert("捕获 body");
}, true);

fatherBox.addEventListener("click", function () {
alert("捕获 father");
}, true);

childBox.addEventListener("click", function () {
alert("捕获 child");
}, true);

补充一个知识点:

在 js中:

  • 如果想获取 body 节点,方法是:document.body

  • 但是,如果想获取 html节点,方法是document.documentElement

冒泡的流程

与捕获的流程相反

事件捕获优先于事件冒泡

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<body>
<button>
<span>我是按钮</span>
</button>
<script>
const html =document.documentElement;
const body= document.body;
const btn = document.querySelector('button');
const sp = document.getElementsByTagName('span')[0];

function theName() {console.log("我是"+this.nodeName)} ;

window.addEventListener("click",theName,false);// 冒泡
document.addEventListener("click",theName,true);// 捕获
html.onclick=theName;// 冒泡
body.addEventListener("click",theName,false);// 冒泡
btn.addEventListener("click",theName,true);// 捕获
sp.addEventListener("click",theName,false);// 冒泡
</script>
</body>

我是#document
我是BUTTON
我是SPAN
我是BODY
我是HTML
我是undefined -->window

Event对象的常见 api 方法

Event 对象代表事件的状态,当dom tree中某个事件被触发的时候,会同时自动产生一个用来描述事件所有的相关信息(比如事件在其中发生的元素、键盘按键的状态、鼠标的位置、鼠标按钮的状态。)的对象,这个对象就是event(事件对象)。

我们来看看下面这几个方法:

方法一 阻止默认事件

1
event.preventDefault();

解释:阻止默认事件。

比如,已知<a>标签绑定了click事件,此时,如果给<a>设置了这个方法,就阻止了链接的默认跳转。

1
2
3
a.addEventListener("click",function(event){
event.preventDefault();
})

方法二:阻止冒泡

这个在业务中很常见。

有的时候,业务中不需要事件进行冒泡。比如说,业务这样要求:单击子元素做事件A,单击父元素做事件B,如果不阻止冒泡的话,出现的问题是:单击子元素时,子元素和父元素都会做事件A。这个时候,就要用到阻止冒泡了。

w3c的方法:(火狐、谷歌、IE11)

1
event.stopPropagation();

IE10以下则是:

1
event.cancelBubble = true;

兼容代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
box3.onclick = function (event) {

alert("child");

//在IE8及以下的浏览器中,是将事件对象作为**window对象的属性**保存的
event = event || window.event;
//阻止冒泡
if (event && event.stopPropagation) {
event.stopPropagation();
} else {
event.cancelBubble = true;
}
}

上方代码中,我们对box3进行了阻止冒泡,产生的效果是:事件不会继续传递到 father、grandfather、body了

属性(事件委托中用到)

1
2
event.currentTarget   //返回绑定事件的元素。在事件委托中,指的是【父元素】。
event.target //返回触发事件的元素。在事件委托中,指的是【子元素】。

上面这两个属性,在事件委托中经常用到。

事件委托

事件委派指将事件统一绑定给元素的共同的祖先元素,这样当后代元素上的事件触发时,会一直冒泡到祖先元素,从而通过祖先元素的响应函数来处理事件。事件委派是利用了冒泡,通过委派可以减少事件绑定的次数,提高程序的性能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<body>
<div style="width:100px;height:50px;background:red">
<button>
<span>我是按钮</span>
</button>
</div>
<div>
<a href="https://www.baidu.com">baidu</a>
</div>
<script>
const html =document.documentElement;
const body= document.body;
const div = document.querySelector('div');
const btn = document.querySelector('button');
const sp = document.getElementsByTagName('span')[0];
const a = document.querySelector('a');


div.addEventListener("click",function(event){
console.log(event.target);
console.log(event.currentTarget);

});

</script>
</body>

将点击事件绑定在div上,依次点击spanbuttondivevent.currentTarget都是返回绑定事件的元素divevent.target则返回触发事件的元素spanbuttondiv

HvyXtO.png