认识事件(Event)
-
Web页面需要经常和用户之间进行交互,而交互的过程中我们可能想要捕捉这个交互的过程:
- 比如用户点击了某个按钮、用户在输入框里面输入了某个文本、用户鼠标经过了某个位置
- 浏览器需要搭建一条JavaScript代码和事件之间的桥梁
- 当某个事件发生时,让JavaScript可以相应(执行某个函数),所以我们需要针对事件编写处理程序(handler)
-
如何进行事件监听呢?
- 事件监听方式一:在script中直接监听(很少使用)
<button id="myButton">Click me!</button> <script> document.getElementById('myButton').onclick = function() { alert('Button clicked (Method 1)'); } </script>
- 事件监听方式二:DOM属性,通过元素的on来监听事件
<script> function buttonClicked() { alert('Button clicked (Method 2)'); } </script> </head> <body> <button id="myButton" onclick="buttonClicked()">Click me!</button> </body>
- 事件监听方式三:通过EventTarget中的addEventListener来监听
<script>
function buttonClicked() {
alert('Button clicked (Method 3)');
}
document.addEventListener('DOMContentLoaded', function() {
document.getElementById('myButton').addEventListener('click', buttonClicked);
});
</script>
</head>
<body>
<button id="myButton">Click me!</button>
</body>
常见的事件列表
- 鼠标事件:
- click —— 当鼠标点击一个元素时(触摸屏设备会在点击时生成)
- mouseover / mouseout —— 当鼠标指针移入/离开一个元素时
- mousedown / mouseup —— 当在元素上按下/释放鼠标按钮时
- mousemove —— 当鼠标移动时
- 键盘事件:
- keydown 和 keyup —— 当按下和松开一个按键时
- 表单(form)元素事件:
- submit —— 当访问者提交了一个 时
- focus —— 当访问者聚焦于一个元素时,例如聚焦于一个
- Document 事件:
- DOMContentLoaded —— 当 HTML 的加载和处理均完成,DOM 被完全构建完成时
- CSS 事件:
- transitionend —— 当一个 CSS 动画完成时
认识事件流
- 事实上对于事件有一个概念叫做事件流,为什么会产生事件流呢?
- 我们可以想到一个问题:当我们在浏览器上对着一个元素点击时,你点击的不仅仅是这个元素本身
- 这是因为我们的HTML元素是存在父子元素叠加层级的
- 比如一个span元素是放在div元素上的,div元素是放在body元素上的,body元素是放在html元素上的
事件冒泡和事件捕获
事件冒泡和事件捕获是浏览器中的两种事件传播机制。当一个事件(例如点击、鼠标移入等)触发时,浏览器会将这个事件按照一定的顺序传递给页面中的元素,以便对事件进行处理。下面我们详细介绍事件冒泡和事件捕获的过程。
- 事件捕获(Event Capturing): 事件捕获是从最外层的祖先元素开始,逐层向内(从上到下)传递直至触发事件的目标元素。事件捕获的目的是在事件到达目标元素之前,提前捕获到这个事件,从而可以在事件到达目标元素之前进行一些处理。需要注意的是,并非所有事件都支持捕获,例如:
mouseenter
、mouseleave
和focus
等事件不支持捕获。- 事件冒泡(Event Bubbling): 与事件捕获相反,事件冒泡是从触发事件的目标元素开始,逐层向外(从下到上)传递直至最外层的祖先元素。事件冒泡的目的是让父元素或祖先元素能够对子元素的事件作出反应。大多数事件都支持冒泡,例如:
click
、mousedown
和mouseup
等。
- 我们会发现默认情况下事件是从最内层的span向外依次传递的顺序,这个顺序我们称之为事件冒泡(Event Bubble)
- 事实上,还有另外一种监听事件流的方式就是从外层到内层(body -> span),这种称之为事件捕获(Event Capture)
- 为什么会产生两种不同的处理流呢?
- 这是因为早期浏览器开发时,不管是IE还是Netscape公司都发现了这个问题
- 但是他们采用了完全相反的事件流来对事件进行了传递
- IE采用了事件冒泡的方式,Netscape采用了事件捕获的方式
- 那么我们如何去监听事件捕获的过程呢?
- 在第三个参数传true,表明我们采用事件监听而不是事件捕获
- 在第三个参数传true,表明我们采用事件监听而不是事件捕获
事件捕获和冒泡的过程
事件捕获和冒泡是浏览器事件处理的两个阶段。当你在一个元素上触发某个事件(如点击)时,浏览器会首先在捕获阶段从根节点向目标元素传播事件,然后在冒泡阶段从目标元素回到根节点。这种机制被称为事件流。
-
如果我们都监听,那么会按照如下顺序来执行:(简略)
- 捕获阶段(Capturing phase):
- 事件(从 Window)向下走近元素。
- 目标阶段(Target phase):
- 事件到达目标元素。
- 冒泡阶段(Bubbling phase):
- 事件从元素上开始冒泡。
详细版本:
- 事件捕获阶段(Event Capturing Phase):事件捕获阶段从根节点(通常是
document
对象)开始,沿着DOM树向下传播,通过每一个祖先节点,一直到达目标元素。在这个阶段,可以在捕获阶段的祖先节点上注册事件处理程序,以在事件达到目标元素之前就对其进行处理。然而,大多数情况下我们并不在捕获阶段处理事件,因为在实际应用中,这种用途并不常见。 - 目标阶段(Target Phase):当事件到达目标元素,就进入了目标阶段。在这个阶段,会触发在目标元素上注册的事件处理程序。
- 事件冒泡阶段(Event Bubbling Phase):事件冒泡阶段从目标元素开始,沿着DOM树向上传播,通过每一个祖先节点,直到根节点。在这个阶段,可以在冒泡阶段的祖先节点上注册事件处理程序,这样当事件从目标元素冒泡上来时就可以进行处理。这种处理事件的方式更常见,因为冒泡阶段提供了在更高级别(如
document
对象)处理事件的机会,这样就可以用少量的事件处理程序来处理大量的事件,这种技术叫做事件委托或事件代理。
注意,有些事件(例如
focus
和blur
)不冒泡,但是它们仍然经历了捕获和目标阶段。另外,你也可以使用event.stopPropagation()
来阻止事件的进一步冒泡或捕获,以防止事件处理程序被过度触发- 事实上,我们可以通过event对象来获取当前的阶段:
- eventPhase
- 开发中通常会使用事件冒泡,所以事件捕获了解即可
- 捕获阶段(Capturing phase):