前端 - Event 那些事儿
一、事件
1. 介绍
- 事件是用来实现js和html之间交互的
- 事件通常与函数配合使用,这样就可以通过发生的事件来驱动函数执行
2. DOM 0级事件与DOM 2级事件
- 区别
a. DOM 0级事件有两种方式:一是在标签中定义,二是在js 中定义,前面的事件会被后面的事件覆盖(js 事件会覆盖标签中的事件)
b. DOM 2级事件在脚本中使用 addEventListener( )给指定元素添加事件
- 0级事件 示例
<!-- 标签中定义 -->
<input id="btn"
type="button"
οnclick="console.log('You clicked the button!');"
value="Click"
/>
<!-- js 中定义 -->
<script>
document.getElementById('btn').onclick = function(){
console.log('I am processed by dom0!');
};
</script>
- 2级事件 示例
document.getElementById('btn').addEventListener('click', function() {
console.log('I am processed by dom2!');
});
document.getElementById('btn').addEventListener('click', function() {
console.log('I am processed by dom2 again!!');
});
// 点击按钮后两个事件均会触发
- 完整代码
<!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>
</head>
<body>
<button id="btn" onclick="console.log('You clicked the button!');">点我</button>
</body>
<script>
/*
document.getElementById('btn').onclick = function(){
console.log('I am processed by dom0!');
};
*/
document.getElementById('btn').addEventListener('click', function() {
console.log('I am processed by dom2!');
});
document.getElementById('btn').addEventListener('click', function() {
console.log('I am processed by dom2 again!!');
});
</script>
</html>
二、DOM 事件流
1.DOM事件流三个阶段
事件捕获阶段,处于目标阶段与事件冒泡阶段
- 事件捕获
从最顶层对象(window)一层一层向下到达目标对象的过程
- 事件捕获
从具体对象(target)一层一层向上传播到达目标对象的过程
顶层对象:不同浏览器不同,部分浏览器为 document
2. DOM事件流
- DOM事件流同时支持两种事件模型:捕获型事件和冒泡型事件
- 捕获型事件在捕获阶段触发,冒泡型事件在冒泡阶段触发,因此捕获型事件先发生
- 两种事件流会触及DOM中的所有对象,从window(document)对象开始,也在window(document)对象结束
3.addEventListener
addEventListener(type, listener[, useCapture])函数
- type:指定事件类型,如 click/mousedown/keypress 等
- listener:监听函数,事件发生时触发
- useCapture:指定事件是冒泡还是捕获型,布尔值,可选,默认设置
false
(既冒泡阶段触发)
三、事件对象
对象代表事件的状态,比如事件在其中发生的元素、键盘按键的状态、鼠标的位置、鼠标按钮的状态
1. 常见属性
- 鼠标/键盘属性
- button 触发事件时的鼠标按键(0-左 1-中 2-右)
- altKey/shiftKey/ctrlKey 对应按键是否按下
- clientX/Y 相对浏览器的坐标(不含滚动条)
- pageX/Y 相对浏览器的坐标(含滚动条)
- screenX/Y 相对屏幕的坐标
- IE属性(IE浏览器支持)
- x/y 同screenX/Y
- offsetX/Y 相对事件源元素的坐标
- srcElement 同 target
- 标准属性
- type 事件的名称
- bubbles 布尔值,是否为冒泡事件类型。
- currentTarget 返回其事件监听器触发该事件的元素
- target 返回触发此事件的元素(事件的目标节点)
二者区别:前者为事件绑定的元素,后者为触发事件的元素
- 标准方法(可用于自定义事件)
- initEvent() 初始化新创建的 Event 对象的属性。
- preventDefault() 通知浏览器不要执行与事件关联的默认动作(如链接跳转、表单提交等)
- stopPropagation() 不再派发事件(阻止冒泡与捕获)
2. 获取对象
<button onclick="console.log(event);;">点我</button>
- 点击按钮,会在控制台打印出事件对象不同浏览器略有差异
四、事件委托(代理)
当监听事件较多时,若给每一个元素都绑定监听函数,对性能会有极大的影响。该问题解决方案为事件委托
事件委托利用了事件冒泡与event.target。只需把监听函数绑定在父容器上即可,便可为子容器绑定事件
1. 示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<style type="text/css">
* {
margin: 5px;
padding: 5px;
}
</style>
<body>
<div id="outer" style="border: 1px green solid">
<div id="inner1" style="border: 1px red solid">This is inner1</div>
<div id="inner2" style="border: 1px red solid">This is inner2</div>
<div id="inner3" style="border: 1px red solid">This is inner3</div>
</div>
</body>
<script>
let outer = document.getElementById('outer');
outer.addEventListener('click', function(event) {
console.log(event.target); //触发事件的元素(结点)
console.log(event.currentTarget); //事件绑定的元素(结点)
// console.log(event.srcElement); //同event.target
}, false);
// 可以针对不同元素绑定不同事件
outer.addEventListener('click', function(event) {
let target = event.target;
switch (target.id) {
case 'inner1':
alert(1);
break;
case 'inner2':
alert(2);
break;
default:
alert(target.innerText);
break;
}
}, false);
// 新增元素会自动绑定事件
let newDiv = document.createElement('div');//创建元素
newDiv.setAttribute('id', 'newDiv');//设置属性
// newDiv.setAttribute('style', 'border: 2px blue solid');//设置属性
// newDiv.style = 'border: 2px blue solid'; // 设置样式(效果同上)
newDiv.style.border = '2px blue solid'; // 设置样式(效果同上)
newDiv.innerHTML = 'This is newDiv created in JavaScript';//设置文本
outer.appendChild(newDiv); //插入子结点
</script>
</html>
2. 效果图
3.总结 (优点)
- 提高性能:每一个函数都会占用内存空间,只需添加一个事件处理程序代理所有事件,所占用的内存空间更少
- 动态监听:使用事件委托可以自动绑定动态添加的元素,即新增的节点不需要主动添加也可以一样具有和其他元素一样的事件