目录
学习来源: https://www.bilibili.com/video/BV1HJ41147DG
1、注册事件
概述
给元素添加事件,称为注册事件或绑定事件。
有两种方式
- 传统方式
- 监听注册方式
事件监听
addEventListener() 事件监听(IE9以后支持)
eventTarget.addEventListener(type, listener[, useCapture])
eventTarget.addEventListener() 方法将指定的监听器注册到 eventTarget(目标对象)上,当该对象触发指定的事件时,就会执行事件处理函数。
该方法接收三个参数:
- type:事件类型字符串,比如 click、mouseover (注意这里不要带 on)
- listener:事件处理函数,事件发生时,会调用该监听函数
- useCapture:可选参数,是一个布尔值,默认是false
attachEvent()事件监听(IE678支持)
eventTarget.attachEvent(eventNameWithOn, callback)
eventTarget.attachEvent() 方法将指定的监听器注册到 eventTarget(目标对象) 上,当该对象触发指定的事件时,指定的回调函数就会被执行。
该方法接收两个参数:
- eventNameWithOn:事件类型字符串,比如 onclick、onmouseover
- callback:事件处理函数,当目标触发事件时回调函数被调用
<body>
<button>传统注册事件</button>
<button>方法监听注册事件</button>
<button>ie9 attachEvent</button>
<script>
var btns = document.querySelectorAll('button');
// 传统方式注册事件
btns[0].onclick = function () {
alert('hi');
}
btns[0].onclick = function () { // 覆盖前面的注册处理函数
alert('hello');
}
// 事件监听 addEventListener
// 里面的事件类型是字符串 必定加引号 而且不带on
// 同一个元素 同一个事件可以添加多个监听器(事件处理程序)
btns[1].addEventListener('click', function () {
alert(22);
})
btns[1].addEventListener('click', function () {
alert(33);
})
// attachEvent ie9以前的版本支持
btns[2].attachEvent('onclick', function () {
alert(11);
})
</script>
</body>
事件监听兼容性解决方案
处理原则:首先照顾大多数浏览器,再处理特殊浏览器
封装一个函数,函数中判断浏览器的类型:
2、删除事件(解绑事件)
- 传统注册方式
eventTarget.onclick = null;
- 方法监听注册方式
eventTarget.removeEventListener(type, listener[, useCapture]);
eventTarget.detachEvent(eventNameWithOn, callback);
示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
div {
width: 100px;
height: 100px;
margin-top: 10px;
background-color: skyblue;
cursor: pointer;
}
</style>
</head>
<body>
<div>1</div>
<div>2</div>
<div>3</div>
<script>
var divs = document.querySelectorAll('div');
divs[0].onclick = function () {
alert(11);
// 传统方式删除事件
divs[0].onclick = null; // 删除后再次点击 div1 无反应
}
// removeEventListener 删除事件
divs[1].addEventListener('click', fn) // 里面的fn 不需要调用加小括号
function fn() {
alert(22);
divs[1].removeEventListener('click', fn); // 删除后再次点击 div2 无反应
}
// detachEvent 删除事件
divs[2].attachEvent('onclick', fn1);
function fn1() {
alert(33);
divs[2].detachEvent('onclick', fn1); // 删除后再次点击 div3 无反应
}
</script>
</body>
</html>
删除事件兼容性解决方案
封装一个函数,函数中判断浏览器的类型:
3、DOM事件流
html中的标签都是相互嵌套的,我们可以将元素想象成一个盒子装一个盒子,document是最外面的大盒子。
当你单击一个div时,同时你也单击了div的父元素,甚至整个页面。
那么是先执行父元素的单击事件,还是先执行div的单击事件 ???
事件流描述的是从页面中接收事件的顺序
例如:给页面中的一个div注册了单击事件,单击了div时,也就单击了body,单击了html,单击了document。
- 事件冒泡:IE最早提出,时间开始时由最具体的元素接收,然后逐级向上传播到DOM最顶层节点的过程。
- 事件捕获:Netscape(网景公司)最早提出,由DOM最顶层节点开始,然后逐级向下传播到最具体的元素接收的过程。
w3c 制定了统一的标准 —–— 先捕获再冒泡
现代浏览器都遵循此标准,所以当事件发生时,会经历3个阶段。
DOM 事件流会经历3个阶段:
- 捕获阶段
- 当前目标阶段
- 冒泡阶段
例如:我们向水里面扔一块石头,首先它会有一个下降的过程,这个过程就可以理解为从最顶层向事件发生的最具体元素(目标点)的捕获过程;之后会产生泡泡,会在最低点( 最具体元素)之后漂浮到水面上,这个过程相当于事件冒泡。
事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程即DOM事件流
注释
- js代码中只能执行捕获或者冒泡其中的一个阶段
- onclick 和 attachEvent 只能得到冒泡阶段
- addEventListener(type, listener[, useCapture]) 第三个参数如果是true,表示在事件捕获阶段调用事件处理程序;如果是false (不写默认就是false),表示在事件冒泡阶段调用事件处理程序。
- 实际开发中很少使用事件捕获,更关注事件冒泡
- 有些事件是没有冒泡的,例如:onblur、onfocus、onmouseenter、onmouseleave
- 事件冒泡有时候会带来麻烦,有时候又会帮助很巧妙的做某些事件。
示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.father {
overflow: hidden;
width: 300px;
height: 300px;
margin: 100px auto;
background-color: pink;
text-align: center;
}
.son {
width: 200px;
height: 200px;
margin: 50px;
background-color: purple;
line-height: 200px;
color: #fff;
}
</style>
</head>
<body>
<div class="father">
<div class="son">son盒子</div>
</div>
<script>
// JS 代码中只能执行捕获或者冒泡其中的一个阶段
// onclick 和 attachEvent(ie) 只能得到冒泡阶段。
</script>
</body>
</html>
事件捕获
// 捕获阶段 如果addEventListener 第三个参数是 true,那么则处于捕获阶段 document -> html -> body -> father -> son
// 给son注册单击事件
var son = document.querySelector('.son');
son.addEventListener('click', function () {
alert('son');
}, true);
// 给father注册单击事件
var father = document.querySelector('.father');
father.addEventListener('click', function () {
alert('father');
}, true); // 点击son盒子,依次弹出father、son;点击father盒子,弹出father
事件冒泡
// 冒泡阶段 如果addEventListener 第三个参数是 false 或者 省略,那么则处于冒泡阶段 son -> father ->body -> html -> document
// 给son注册单击事件
var son = document.querySelector('.son');
son.addEventListener('click', function () {
alert('son');
}, false);
// 给father注册单击事件
var father = document.querySelector('.father');
father.addEventListener('click', function () {
alert('father');
}, false);
// 给document注册单击事件,省略第3个参数(效果同false)
document.addEventListener('click', function () {
alert('document');
}) // 点击son盒子,依次弹出son、father、document;点击father盒子,依次弹出father、document;点击document盒子,弹出document