前言
JavaScript里面的事件系统一直感觉是个既简单又复杂的东西,简单的是大家习惯上用vue或react这样的框架去绑定,复杂的是在不用框架的情况下发现各个浏览器对于事件的处理有所不同。导致这种现象其实是因为JavaScript的事件系统在早期的时候一直没有一个规范,事件的实现也是有各大浏览器厂商自己开发制定的,所以长期起来出现了各种奇葩的兼容性写法。今天我们来简单搞一搞事件的一些关键点。
一、事件流
事件流描述了页面接收事件的顺序。由于刚开始并没有指定相应的规范,各浏览器厂家在实现事件流的时候都是自己去定义的,有意思的是IE和Netscape开发团队提出了几乎完全相反的事件流方案。IE将支持事件冒泡流,而NetscapeCommunicator将支持事件捕获流。
- 事件冒泡
IE事件流被称为事件冒泡,这是因为事件被定义为从最具体的元素(文档树中最深的节点)开始触发,然后向上传播至没有那么具体的元素(文档)。他的触发顺序其实是从你点击的最小那个节点开始,逐步向父级冒泡,直到冒泡到顶级或者被阻止冒泡
- 事件捕获
Netscape Communicator团队提出了另一种名为事件捕获的事件流。事件捕获的意思是最不具体的节点应该最先收到事件,而最具体的节点应该最后收到事件。事件捕获实际上是为了在事件到达最终目标前拦截事件。也就是他的顺序是从最上层那个父节点开始,一直到最小的具体节点。
现代浏览器对于这两种事件流都支持,事件的触发都是先从捕获阶段然后到冒泡阶段的,开发的时候可以根据需要在不同的阶段进行处理
二、浏览器事件绑定
- DOM0事件处理程序
在JavaScript中指定事件处理程序的传统方式是把一个函数赋值给(DOM元素的)一个事件处理程序性。这也是在第四代Web浏览器中开始支持的事件处理程序赋值方法,直到现在所有现代浏览器仍然都支持此方法,主要原因是简单。要使用JavaScript指定事件处理程序,必须先取得要操作对象的引用。以这种方式添加事件处理程序是注册在事件流的冒泡阶段的。像这样使用DOM0方式为事件处理程序赋值时事件处理程序会在元素的作用域中运行,即this等于元素
let btn = document.getElementById("myBtn");
btn.onclick = function() {
console.log("Clicked");
};
- DOM2事件处理程序
DOM2 Events为事件处理程序的赋值和移除定义了两个方法:addEventListener()和removeEventListener()。这两个方法暴露在所有DOM节点上,它们接收3个参数:事件名、事件处理函数和一个布尔值,true表示在捕获阶段调用事件处理程序,false(默认值)表示在冒泡阶段调用事件处理程序。使用这种方式绑定事件,this值等于元素本身
let btn = document.getElementById("myBtn");
btn.addEventListener("click", function() {
console.log(this.id);
}, false);
- IE事件处理程序
IE实现了与DOM类似的方法,即attachEvent()和detachEvent()。这两个方法接收两个同样的参数:事件处理程序的名字和事件处理函数。因为IE8及更早版本只支持事件冒泡,所以使用attachEvent()添加的事件处理程序会添加到冒泡阶段。使用attachEvent()时,事件处理程序是在全局作用域中运行的,因此this等于window
var btn = document.getElementById("myBtn");
btn.attachEvent("onclick", function() {
console.log("Clicked");
});
- 跨浏览器事件处理程序
为了以跨浏览器兼容的方式处理事件,很多开发者会选择使用一个JavaScript 库,其中抽象了不同浏览器的差异。
var EventUtil = {
addHandler: function(element, type, handler) {
if (element.addEventListener) {
element.addEventListener(type, handler, false);
} else if (element.attachEvent) {
element.attachEvent("on" + type, handler);
} else {
element["on" + type] = handler;
}
},
removeHandler: function(element, type, handler) {
if (element.removeEventListener) {
element.removeEventListener(type, handler, false);
} else if (element.detachEvent) {
element.detachEvent("on" + type, handler);
} else {
element["on" + type] = null;
}
}
};
三、事件对象
在DOM中发生事件时,所有相关信息都会被收集并存储在一个名为event的对象中。这个对象包含了一些基本信息,比如导致事件的元素、发生的事件类型,以及可能与特定事件相关的任何其他数据。例如,鼠标操作导致的事件会生成鼠标位置信息,而键盘操作导致的事件会生成与被按下的键有关的信息。所有浏览器都支持这个event对象,尽管支持方式不同。
- DOM事件对象
在DOM合规的浏览器中,event对象是传给事件处理程序的唯一参数。不管以哪 种方式(DOM0或DOM2)指定事件处理程序,都会传入这个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 对象属性如下:
bubbles | 只读 | 表示事件是否冒泡 | cancelable | 只读 | 表示是否可以取消事件的默认行为 | currentTarget | 只读 | 当前事件处理程序所在的元素 | defaultPrevented | 只读 | true表示已经调用preventDefault()方法(DOM3 Events中新增) | detail | 只读 | 事件相关的其他信息 | eventPhase | 只读 | 表示调用事件处理程序的阶段:1代表捕获阶段,2代表到达目标,3代表冒泡阶段 | preventDefault() | 只读 | 用于取消事件的默认行为。只有cancelable为true才可以调用这个方法 | stopImmediatePropagation() | 只读 | 用于取消所有后续事件捕获或事件冒泡,并阻止调用任何后续事件处理程序(DOM3 Events中新增) | stopPropagation() | 只读 | 用于取消所有后续事件捕获或事件冒泡。只有bubbles为true才可以调用这个方法 | target | 只读 | 事件目标 | trusted | 只读 | true表示事件是由浏览器生成的。false表示事件是开发者通过JavaScript创建的 (DOM3 Events中新增) | type | 只读 | 被触发的事件类型 | View | 只读 | 与事件相关的抽象视图。等于事件所发生的window对象 |
需要特别注意的是:在事件处理程序内部,this对象始终等于eveng.currentTarget的值,而eveng.target只包含事件的实际目标。 如果事件处理程序直接添加在了意图的目标,则this、currentTarget和target的值是一样的。
- IE事件对象
与DOM事件对象不同, IE事件对象可以基于事件处理程序被指定的方式以不同方 式来访问。如果事件处理程序是使用DOM0方式指定的,则event对象只是 window对象的一个属性,如下所示:
var btn = document.getElementById("myBtn");
btn.onclick = function() {
let event = window.event;
console.log(event.type); // "click"
};
如果事件处理程序是使 用attachEvent()指定的,则event对象会作为唯一的参数传给处理函数
var btn = document.getElementById("myBtn");
btn.attachEvent("onclick", function(event) {
console.log(event.type); // "click"
});
IE基于触发的事件类型不同,event对象中包含的属性和方法也不一样。不过,所有IE事件对象都会包含下表所列的公共属性和方法。
cancelBubble | 读写 | 默认为false,设置为true可以取消冒泡(与DOM的 stopPropagation()方法相同) | returnValue | 读写 | 默认为true,设置为false可以取消事件默认行为(与DOM的 preventDefault()方法相同) | srcElement | 只读 | 事件目标(与DOM的target属性相同) | type | 只读 | 被触发的事件类型 |
- 跨浏览器事件对象
虽然event对象不尽相同,但是我们依然可以根据属性封装出一些共通的方法。
var EventUtil = {
addHandler: function(element, type, handler) {
// 为节省版面,删除了之前的代码
},
removeHandler: function(element, type, handler) {
// 为节省版面,删除了之前的代码
},
getEvent: function(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;
}
},
stopPropagation: function(event) {
if (event.stopPropagation) {
event.stopPropagation();
} else {
event.cancelBubble = true;
}
}
};
结语
以上就是本文对于JavaScript事件画重点的全部内容了,事实上JavaScript事件的细节还有很多,但是篇幅有限,估计各位看官也没多大耐心看。我个人觉得对于JavaScript事件,如果掌握到了事件流、事件绑定方法、以及事件对象这三个东西,基本上已经能掌握事件的运用了,尤其重要的是我们要懂得兼容各浏览器的事件处理写法。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!