九、事件
浏览器设计的一套处理用户行为的机制。
所谓的事件,是浏览器监听用户行为的一种机制。
- 当用户使用鼠标
点击
一个按钮,会触发该按钮的点击
事件 如果此时我们想要执行代码 就可以通过JS脚本设置点击
事件的处理函数 - 用户鼠标双击一个按钮,会触发该按钮的双击事件
- …
类似的事件还有很多
9.1 事件的分类
1. 鼠标事件
- click 点击事件(一次click包含一次mousedown和 一次mouseup)
- dblclick 双击事件
- mousedown 鼠标按下事件
- mouseup 鼠标抬起事件
- mouseover 鼠标进入事件
- mouseenter 鼠标进入事件
- mouseout 鼠标离开事件
- mouseleave 鼠标离开事件
- mousemove 鼠标移动事件
2. 键盘事件
- keydown 键盘键被按下
- keyup 键盘键被松开
- keypress 输入
3. 浏览器的事件
- load 页面中所有资源都被加载完毕的时候
- scroll 页面的卷动
4. 焦点事件
- focus 当一个元素获取到焦点时
- blur 当一个元素失去焦点时
5. 移动端事件
- touchstart 触摸开始事件 会在手指按下的时候触发
- touchmove 触摸并移动 会在手指按下并移动的时候触发
- touchend 触摸结束事件 会在手指离开的时候触发
6. 其它事件
- animationstart 动画开始时触发
- animationend 动画结束时触发
- transitionend 过渡结束时触发
9.2 事件的组成
- 元素(也叫作事件源)
- 事件类型(类型,见9.1)
-
9.3 事件流程
事件冒泡:当点击时 事件从最精确的元素 一层一层往上触发 直到最顶层元素 这个过程叫做事件冒泡
事件捕获:当点击时 事件从最顶层元素 一层一层的往下触发 直到最精确元素 这个过程叫做事件捕获
altKey 热键alt键
- ctrlKey 热键ctrl键
- shiftKey 热键shift键以上属性都是布尔值,表示是否按下,没有按下为false,按下为true
- offsetX 事件发生时鼠标位于元素内部的left位置(从鼠标位置到左边框内)
- offsetY 事件发生时鼠标位于元素内部的top位置(从鼠标位置到上边框内)
- clientX 事件发生时鼠标到视口的左边距离
- clientY 事件发生时鼠标到视口的上边距离
- pageX 事件发生时鼠标到页面的左边距离(IE中无该属性,因为有版心的缘故,通常e.clientX就是e.pageX)
- pageY 事件发生时鼠标到页面的上边距离(IE中无该属性,可以通过e.clientY + 页面卷动值来获取)
- currentTarget 绑定事件的元素(IE中没有该属性)
- target 触发事件的元素(IE中没有该属性,而是叫做 srcElement)
键盘事件的重要属性
- key 表示当前的键对应的字符
-
9.5 阻止冒泡
高级浏览器中 可以通过e.stopPropagation() 进行阻止事件的冒泡
// 高级浏览器中
// box1是box2的父元素
var box1 = document.querySelector(".box1");
var box2 = document.querySelector(".box2");
box1.onclick = function() {
console.log("这是BOX1");
}
box2.onclick = function(e) {
e.stopPropagation();
console.log("这是BOX2");
}
IE浏览器中 可以通过e.cancelBubble = true 进行阻止事件的冒泡
// IE浏览器中
// box1是box2的父元素
var box1 = document.querySelector(".box1");
var box2 = document.querySelector(".box2");
box1.onclick = function() {
console.log("这是BOX1");
}
box2.onclick = function(e) {
var e = e || window.event;
e.cancelBubble = true;
console.log("这是BOX2");
}
9.6 停止默认行为
浏览器的一些事件中,带有一些默认行为 比如a标签的点击事件中 会带有跳转页面的行为 表单的点击事件中 带有提交的默认行为 滚轮事件中 带有改变页面卷动值的默认行为
高级浏览器中 可以通过 e.preventDefault() 阻止默认行为
// 获取元素
var a = document.getElementsByTagName("a")[0];
// 设置点击事件
a.addEventListener("click", function(e) {
console.log("点击了a标签1111");
e.preventDefault();
}, false);
IE浏览器中 可以通过 e.returnValue = true; 阻止默认行为
// 获取元素
var a = document.getElementsByTagName("a")[0];
// 设置点击事件
a.attachEvent("onclick", function(e) {
console.log("点击了a标签1111");
e.returnValue = true;
});
DOM0级事件绑定方式中,可以通过return false进行阻止默认行为
// 获取元素
var a = document.getElementsByTagName("a")[0];
// 设置点击事件
a.onclick = function() {
return false;
}
9.7 事件绑定
DOM0级
- 绑定
- 元素.on事件类型 = 事件函数
- 只能够绑定一个事件 因为它是对属性进行赋值
- 元素.on事件类型 = 事件函数
- 移除
- 元素.on事件类型 = null
我们都知道,一个对象的属性只能够保存一个值。 如果对一个对象属性进行多次赋值,后面赋值的属性会替换掉前面的属性
- 元素.on事件类型 = null
- 绑定
DOM2级
- 绑定
- dom.addEventListener(type, handler, boolean)
- type: 事件类型字符串 不带on
- handler: 事件处理函数
- boolean: 布尔值 决定绑定到捕获阶段还是冒泡阶段 默认是false false表示冒泡
- type: 事件类型字符串 不带on
- dom.addEventListener(type, handler, boolean)
- 结论: 可以通过addEventListener方法进行多个事件函数的绑定 执行时是按照代码的书写顺序执行 因为代码的书写顺序决定了绑定顺序
- 移除
- document.removeEventListener(type, handler, boolean);
- type: 事件类型字符串 不带on
- handler: 事件处理函数 一定要保证函数地址是绑定的那个
- boolean: 布尔值 决定移除的是捕获阶段还是冒泡阶段 默认是false false表示冒泡
结论: 第二个参数是要移除的函数 函数是引用类型 引用类型的比较的是地址 所以一定要保证 移除的函数是当初绑定的那个函数本身
- type: 事件类型字符串 不带on
- document.removeEventListener(type, handler, boolean);
- 绑定
IE中的高级绑定方式(非DOM2级)
- 绑定方式:
- dom.attachEvent(type, handler);
- type: 事件类型字符串 带on
- handler: 事件处理函数
- 没有第三个参数 意味着不能够绑定到捕获阶段特点: 可以对同一个元素绑定多个同类型事件的处理函数 执行起来是倒着执行 先绑定的后执行 后绑定的先执行
- type: 事件类型字符串 带on
- dom.attachEvent(type, handler);
- 移除方式:
- dom.detachEvent(type, handler);
- type: 事件类型字符串 带on
- handler: 事件处理函数 要注意函数的地址问题
9.8 事件委托
事件委托也叫作事件代理。是一种设计模式。
思想: 将原本子元素做的事情,委托给父元素去做。将事件绑定给父元素,父元素事件触发时,通过e.target判定触发事件的元素。决定执行对应代码// 1 获取元素 获取不可能被移除的父元素
var tbody = document.querySelector("tbody");
// 2 给tbody绑定事件
tbody.onclick = function(e) {
// e.target 这个属性指向触发事件的元素
console.log(e.target)
// 判定 点击到的是什么
if (e.target.className === "del") {
// 点击到的是移除按钮
e.target.parentNode.remove();
}
}
9.9 循环绑定事件时i的问题
循环绑定事件
点击时:var arr = [li, li, li];
for (var i = 0; i < arr.length; i++) {
arr[i].onclick = function() {
console.log(i);
}
}
发现问题:点击时因为循环已经结束,所以输出的是3。而不是预想中的 0 1 2.
- type: 事件类型字符串 带on
- dom.detachEvent(type, handler);
- 绑定方式:
可是有时候我们需要用到这个循环变量当时的值,而不是循环结束后的值。
解决方案1: 添加自定义JS属性
for (let i = 0; i < arr.length; i++) {
// 1 给每一个元素 添加一个自定义的JS属性
arr[i].index = i;
arr[i].onclick = function() {
// 再在函数中,通过this访问自定义属性
console.log(this.shuaindexige)
}
}
结果:
解决方案2: IIFE
for (var i = 0; i < arr.length; i++) {
// 2 IIFE解决循环问题
(function(m) {
arr[m].onclick = function() {
console.log(m)
}
})(i)
}
原理如下图:
解决方案3:数组的forEach方法
arr.forEach(function(value, index) {
value.onclick = function() {
console.log(index)
}
})