事件冒泡
事件冒泡即事件开始时由最具体的元素(最"近"的节点)接收,然后逐级向上传播到较为不具体的节点(文档)
<!DOCTYPE html>
<html>
<head>
<title>Click</title>
</head>
<body>
<div id="myDiv">Click Me</div>
</body>
</html>
以上 HTML 页面中,当点击<div>
元素时,click 事件的传递顺序是这样的: div -> body -> html -> document。所有现代浏览器都支持事件冒泡,但具体实现上有差异。
事件捕获
事件捕获的思想是事件开始时由最不具体的元素(最"远"的节点)接收,最具体的元素最后接收到事件。
以之前的 HTML 代码为例,click 事件的传递顺序是这样的:document -> html -> body -> div。老版本的浏览器不支持事件捕获,所以不推荐使用事件捕获。
事件模型
事件的名字包括 click、load 和 mouseover 等,而响应某个事件的函数叫做事件处理程序(或事件侦听器、事件句柄),事件处理程序的名字以"on"开头,为事件指定处理程序的方式有多种。
事件模型分为三种:
●原始事件模型(DOM0级);
●标准事件模型(DOM2级);
●IE事件模型(基本不用了,以下不作描述);
原始事件模型
原始事件模型的特点有:
●绑定速度快,具有很好的跨浏览器优势;
●只支持冒泡,不支持捕获;
●同一个类型的事件只能绑定一次;
绑定方式有以下两种:
1) 方式一
HTML 代码:
<input type="button" value="click" onclick="clickhandle()" />
JavaScript 代码:
function clickHandle() {
alert("Hello");
}
2) 方式二
HTML 代码:
<input id="btn" type="button" value="click" />
JavaScript 代码:
var btn = document.getElementById("btn");
btn.onclick = function() {
alert(this.value);
}
事件处理程序中,this 对象引用的是绑定事件处理程序的元素节点。
删除事件处理程序的方法:
btn.onclick = null;
标准事件模型
DOM2 级事件给元素节点定义了addEventListener()
和removeEventListener()
方法,分别用于绑定事件处理程序和删除事件处理程序。这两个方法都接收3个参数:要处理的事件名、作为事件处理程序的绑定函数和一个可选布尔值(默认为 false,通常不需要手动设置),第三个布尔值为 true 表示在捕获阶段调用事件处
IE9以上及其他流行的浏览器都支持 DOM2 级事件处理程序。
HTML 代码:
<input id="btn" type="button" value="click" />
JavaScript 代码:
var btn = document.getElementById("btn");
function clickHandle() {
alert(this.value);
}
btn.addEventListener("click", clickHandle);
// 5秒后点击按钮将不会有任何反应
setTimeout(function() {
console.log("Stop");
btn.removeEventListener("click", clickHandle);
}, 5000);
注意,removeEventListener()
第二个参数为具体的事件处理程序函数名,如果需要删除指定事件处理程序,则应先将该事件处理程序定义为普通函数而不是直接使用匿名函数。
事件对象
触发一个事件时,会产生一个事件对象,这个事件对象中包含所有与事件有关的信息。
在事件处理程序中可以访问这个事件对象。
var btn = document.getElementById("btn");
btn.onclick = function(event) {
alert(event.type); // 输出事件类型: "click"
}
事件对象常用的属性及方法:
- e.target:只读,返回事件的目标(直接触发的元素节点);
- e.type:只读,返回事件类型;
- e.preventDefault():取消事件的默认行为,常用场景有取消提交按钮的点击提交行为及阻止链接点击跳转等,等同于return false;
- e.stopPropagation():取消事件进一步捕获或冒泡。
事件类型
UI事件
UI 事件指那些不一定与用户操作有关的事件。
常用的 UI 事件有:
- load:页面、图像、脚本等资源完全加载后触发的事件,应用场景:图片加载完全前加入载入一个预备显示图片;
- select:用户选择文本框;
- scroll:滚动带滚动条的元素时触发,应用场景: 返回顶部按钮。
鼠标事件
鼠标事件是最常用的一类事件。
常用的鼠标事件:
- click:单击鼠标左键或按回车键触发;
- dblclick:双击鼠标触发;
- mousedown:用户按下任意鼠标键时触发;
- mouseenter:鼠标移入元素触发;
- mouseleave:鼠标移出元素触发;
- mousemove:鼠标在元素上移动时触发。
鼠标事件触发元素的事件对象上设置有两个表示客户区(页面显示的区域)坐标的属性:clientX 属性(相对左上角点的水平坐标)和 clientY 属性(相对左上角点的竖直坐标)。
键盘事件
用户使用键盘时会触发键盘事件。
常用的键盘事件:
- keydown:按下任意键时触发,按住不放会重复触发;
- keypress:按下字符键时触发,按住不放会重复触发;
- keyup:释放按键时触发。
键盘事件触发元素的事件对象上设置有 keyCode 属性,用于返回按下的键对应的键码。对于 130事件,触发元素事件对象上的 charCode 属性可以返回按下的字符键对应的 ASCII 码。
自定义事件
var dom = document.getElementById('el');
// 注册事件,不可以添加参数
var eve1 = new Event("myClick")
// 可以添加参数
var eve2 = new CustomEvent('myClick',params)
// 监听事件
dom.addEventListener("myClick",function () {
console.log("myClick");
});
// 触发事件
dom.dispatchEvent(eve1);
事件代理
给一个列表中的子项绑定事件处理程序,我们一般会这么做:
// 1. 获取DOM Element
var colorListEl = document.querySelector(".color_list");
var colors = colorListEl.getElementsByTagName("li");
var box = document.querySelector(".box");
// 2. 逐个绑定事件处理程序
for (var n = 0; n < colors.length; n++) {
colors[n].addEventListener("click", function () {
console.log(this.innerHTML);
box.innerHTML = "该颜色为 " + this.innerHTML;
});
}
这种做法在 li 较少的时候可以使用,但如果有一万个 li ,那就会导致性能降低。此时就需要使用事件代理来进行优化了,具体做法是:
function colorChange(e) {
var e = e || window.event; // 兼容性的处理
if (e.target.nodeName.toLowerCase() === "li") {
box.innerHTML = "该颜色为 " + e.target.innerHTML;
}
}
colorListEl.addEventListener("click", colorChange);
由于事件冒泡机制,点击了 li 后会冒泡到 ul ,此时就会触发绑定在 ul 上的点击事件,再利用 target 找到事件实际发生的元素,就可以达到预期的效果。
使用事件代理的好处不仅在于将多个事件处理函数减为一个,而且对于不同的元素可以有不同的处理方法。假如上述列表元素当中添加了其他的元素节点(如:a、span等),我们不必再一次循环给每一个元素绑定事件,直接修改事件代理的事件处理函数即可。