一 定义
在 DOM 中发生事件时,所有相关信息都会被收集并存储在一个名为 event 的对象中
- 一些基本信息,比如导致事件的元素、发生的事件类型,以及可能与特定事件相关的任何其他数据
二 DOM事件对象
1、事件对象:
- 在DOM合规的浏览器中,以DOM0或DOM2的方式指定事件处理程序,event对象是传给事件处理程序的唯一参数
- 事件对象包含与特定事件相关的属性和方法
- event 对象只在事件处理程序执行期间存在,一旦执行完毕,就会被销毁
let btn = document.getElementById("myBtn");
btn.onclick = function(event) {
console.log(event.type); // "click"
};
btn.addEventListener("click", (event) => {
console.log(event.type); // "click"
}, false);
// 这个例子中的两个事件处理程序都会在控制台打出 event.type 属性包含的事件类型。
// 这个属性中始终包含被触发事件的类型,如"click"(与传给 addEventListener()和removeEventListener()方法的事件名一致)
2、公共属性和方法:
事件处理程序添加的对象不同会造成什么影响?
- 直接添加在意图的目标:this、currentTarget 和 target 的值是一样
- this 对象始终等于 currentTarget 的值
- target 只包含事件的实际目标
let btn = document.getElementById("myBtn"); btn.onclick = function(event) { console.log(event.currentTarget === this); // true console.log(event.target === this); // true }; // 上面的代码检测了 currentTarget 和 target 的值是否等于 this。因为 click 事件的目标是按钮,所以这 3 个值是相等的。
- 在要操作目标元素的父节点上添加
- this 和 currentTarget 都等于 父节点,这是因为它是注册事件处理程序的元素
- target 属性等于按钮本身,这是因为那才是 操作事件真正的目标
// 如果这个事件处理程序是添加到按钮的父节点(如 document.body)上,那么它们的值就不一样了。比如下面的例子在 document.body 上添加了单击处理程序: document.body.onclick = function(event) { console.log(event.currentTarget === document.body); // true console.log(this === document.body); // true console.log(event.target === document.getElementById("myBtn")); // true }; // 这种情况下点击按钮,this 和 currentTarget 都等于 document.body,这是因为它是注册事件处理程序的元素。而 target 属性等于按钮本身,这是因为那才是 click 事件真正的目标。由于按钮本身并没有注册事件处理程序,因此 click 事件冒泡到 document.body,从而触发了在它上面注册的处理程序。
3、重点方法
- event.type:type 属性在一个处理程序处理多个事件时很有用
let btn = document.getElementById("myBtn");
let handler = function(event) {
switch(event.type) {
case "click":
console.log("Clicked");
break;
case "mouseover":
event.target.style.backgroundColor = "red";
break;
case "mouseout":
event.target.style.backgroundColor = "";
break;
}
};
btn.onclick = handler;
btn.onmouseover = handler;
btn.onmouseout = handler;
// 在这个例子中,函数 handler 被用于处理 3 种不同的事件:click、mouseover 和 mouseout。当按钮被点击时,应该在控制台打印一条消息,如前面的例子所示。而把鼠标放到按钮上,会导致按钮背景变成红色,接着把鼠标从按钮上移开,背景颜色应该又恢复成默认值。这个函数使用 event.type属性确定了事件类型,从而可以做出不同的响应
- preventDefault():用于阻止特定事件的默认动作
任何可以通过 preventDefault()取消默认行为的事件,其事件对象的 cancelable 属性都会设置为 true
// 链接的默认行为就是在被单击时导航到 href 属性指定的 URL。如果想阻止这个导航行为,可以在 onclick 事件处理程序中取消
let link = document.getElementById("myLink");
link.onclick = function(event) {
event.preventDefault();
};
- stopPropagation():用于立即阻止事件流在 DOM 结构中传播,取消后续的事件捕获或冒泡
// 直接添加到按钮的事件处理程序中调用 stopPropagation(),可以阻止 document.body 上注册的事件处理程序执行。比如:
let btn = document.getElementById("myBtn");
btn.onclick = function(event) {
console.log("Clicked");
event.stopPropagation();
};
document.body.onclick = function(event) {
console.log("Body clicked");
};
// 如果这个例子中不调用stopPropagation(),那么点击按钮就会打印两条消息。但这里由于click事件不会传播到 document.body,因此 onclick 事件处理程序永远不会执行
- eventPhase 属性:可用于确定事件流当前所处的阶段
- 如果事件处理程序在捕获阶段被调用,则 eventPhase 等于 1
- 如果事件处理程序在目标上被调用,则 eventPhase 等于 2
- 如果事件处理程序在冒泡阶段被调用,则 eventPhase 等于 3
- 不过要注意的是,虽然“到达目标”是在冒泡阶段发生的, 但其 eventPhase 仍然等于 2
let btn = document.getElementById("myBtn");
btn.onclick = function(event) {
console.log(event.eventPhase); // 2
};
document.body.addEventListener("click", (event) => {
console.log(event.eventPhase); // 1
}, true);
document.body.onclick = (event) => {
console.log(event.eventPhase); // 3
};
// 在这个例子中,点击按钮首先会触发注册在捕获阶段的 document.body 上的事件处理程序,显示eventPhase 为 1
// 接着,会触发按钮本身的事件处理程序(尽管是注册在冒泡阶段),此时显示 eventPhase 等于 2
// 最后触发的是注册在冒泡阶段的 document.body 上的事件处理程序,显示eventPhase 为 3
// 而当 eventPhase 等于 2 时,this、target 和 currentTarget 三者相等。
三 IE事件对象
定义:IE 事件对象可以基于事件处理程序被指定的方式以不同方式来访问
// 场景一: DOM0 方式
// 事件处理程序是使用 DOM0 方式指定的,则 event 对象只是 window 对象的一个属性,如下所示:
var btn = document.getElementById("myBtn");
btn.onclick = function() {
let event = window.event;
console.log(event.type); // "click"
};
//这里,window.event 中保存着 event 对象,其 event.type 属性保存着事件类型(IE 的这个属性的值与 DOM 事件对象中一样)
// 场景二:IE方法
// 如果事件处理程序是使用 attachEvent()指定的,则 event对象会作为唯一的参数传给处理函数,如下所示:
var btn = document.getElementById("myBtn");
btn.attachEvent("onclick", function(event) {
console.log(event.type); // "click"
});
//使用 attachEvent()时,event 对象仍然是 window 对象的属性(像 DOM0 方式那样),只是出于方便也将其作为参数传入。
//场景三:HTML
//如果是使用 HTML 属性方式指定的事件处理程序,则 event 对象同样可以通过变量 event 访问(与DOM 模型一样)。下面是在 HTML 事件属性中使用 event.type 的例子:
<input type="button" value="Click Me" onclick="console.log(event.type)">
1、属性方法
2、this作用域
- 由于事件处理程序的作用域取决于指定它的方式,因此 this 值并不总是等于事件目标
- 不同事件对象上的 srcElement 属性中保存的都是事件目标
//更好的方式是使用事件对象的 srcElement 属性代替 this。下面的例子表明,不同事件对象上的srcElement 属性中保存的都是事件目标:
var btn = document.getElementById("myBtn");
btn.onclick = function() {
console.log(window.event.srcElement === this); // true
};
btn.attachEvent("onclick", function(event) {
console.log(event.srcElement === this); // false
});
// 在第一个以 DOM0 方式指定的事件处理程序中,srcElement 属性等于 this,而在第二个事件处理程序中(运行在全局作用域下),两个值就不相等了
3、returnValue 属性
等价于 DOM 的 preventDefault()方法,都是用于取消给定事件默认的行为
// 只不过在这里要把 returnValue 设置为 false 才是阻止默认动作。下面是一个设置该属性的例子:
var link = document.getElementById("myLink");
link.onclick = function() {
window.event.returnValue = false;
};
// 在这个例子中,returnValue 在 onclick 事件处理程序中被设置为 false,阻止了链接的默认行为
// 与 DOM 不同,没有办法通过 JavaScript 确定事件是否可以被取消
4、cancelBubble 属性
与 DOMstopPropagation()方法用途一样,都可以阻止事件冒泡。因为 IE8 及更早版本不支持捕获阶段,所以只会取消冒泡。stopPropagation()则既取消捕获也取消冒泡
// 下面是一个取消冒泡的例子:
var btn = document.getElementById("myBtn");
btn.onclick = function() {
console.log("Clicked");
window.event.cancelBubble = true;
};
document.body.onclick = function() {
console.log("Body clicked");
};
// 通过在按钮的 onclick 事件处理程序中将 cancelBubble 设置为 true,可以阻止事件冒泡到document.body,也就阻止了调用注册在它上面的事件处理程序。于是,点击按钮只会输出一条消息
四 跨浏览器事件对象
定义:
- 虽然 DOM 和 IE 的事件对象并不相同,但它们有足够的相似性可以实现跨浏览器方案
- DOM 事件对象中包含 IE 事件对象的所有信息和能力,只是形式不同。这些共性可让两种事件模型之间的映射成为可能
var EventUtil = {
addHandler: function(element, type, handler) {
// 为节省版面,删除了之前的代码
},
getEvent: function(event) { //其返回对 event 对象的引用
return event ? event : window.event;
},
getTarget: function(event) { //其返回事件目标
return event.target || event.srcElement;
},
preventDefault: function(event) { //其用于阻止事件的默认行为
if (event.preventDefault) {
event.preventDefault();
} else {
event.returnValue = false;
}
},
removeHandler: function(element, type, handler) {
// 为节省版面,删除了之前的代码
},
stopPropagation: function(event) { //先检测用于停止事件流的 DOM 方法,如果没有再使用 cancelBubble 属性
if (event.stopPropagation) {
event.stopPropagation();
} else {
event.cancelBubble = true;
}
}
};