事件基础
- 事件是用户或浏览器触发的动作,如点击按钮、移动鼠标、按下键盘等。
- 事件是交互式网页的核心,允许网页响应用户的操作。
事件类型
我们常见的事件类型包括:
- MouseEvent:与鼠标相关的事件,如 click、mouseover 等。它提供了鼠标事件特有的属性,如 clientX、clientY、screenX、screenY 等。
- KeyboardEvent:与键盘相关的事件,如 keydown、keyup。它提供了键盘事件特有的属性,如 key、shiftKey、ctrlKey 等。
- UIEvent:与用户界面相关的事件:如 load、unload、resize、scroll 等。它提供了一些通用的属性,如 view(指向与事件相关的试图(window 对象))。
- DragEvent:与拖放操作相关的事件,如 dragstart、dragend 等。它提供了拖放事件特有的特性,如 dataTransfer 等。
- FocusEvent:与焦点相关的事件,如 focus、blur 等。它提供了焦点事件特有的属性,如 relatedTarget(指向失去焦点的元素)。
- ProgressEvent:与进度相关的事件,如 loadstart、progress、abort 等。它提供了如 lengthComputable、loaded、total 等特有属性。
- WheelEvent:与鼠标滚轮相关的事件,如 wheel。它提供了如 deltaX、deltaY 等特有属性。
另外,我们还可以通过 CustomEvent 自定义事件。所有的事件都继承自 Event。
事件处理
- 我们可以 HTML 元素的事件属性(如 onclick 等)绑定事件,也可以通过 addEventListener 方法添加时间监听。
- addEventListener:element.addEventListener(event, handleFunction, useCapture)
- 在使用 addEventListener 时,需要主动 removeEventListener,避免内存泄漏和重复触发。
- 事件传播包括:
-
- 捕获阶段:事件从根节点向下传播到目标节点的过程中。
- 目标阶段:事件到达目标节点时。
- 冒泡阶段:事件从根节点向上传播到根节点的过程。
在前端框架中不推荐使用 addEventListener
- 生命周期管理:React 和 Vue 都会在组件卸载时清理它们添加的事件监听器。如果你使用了 addEventListener,需要确保在组件卸载时手动移除这些监听器,否则可能导致内存泄漏。
- 性能优化:框架的事件处理通常经过了优化,以适应其自身的更新和渲染机制。
- 代码简洁性:使用框架提供的时间处理方式可以是代码更简洁,更符合框架的使用习惯。
处理 resize 事件
React
import { useState, useEffect } from 'react';
import { debounce } from 'lodash';
const ListenResize = () => {
const [windowSize, setWindowSize] = useState({
width: window.innerWidth,
height: window.innerHeight,
})
const handelResize = debounce(() => {
setWindowSize({
width: window.innerWidth,
height: window.innerHeight,
})
}, 300)
useEffect(() => {
window.addEventListener('resize', handelResize);
return () => {
window.removeEventListener('resize', handelResize);
}
}, [])
return (
<div>
<div>宽:{windowSize.width}</div>
<div>高:{windowSize.height}</div>
</div>
)
}
export default ListenResize
Vue
<template>
<div>
<div>宽:{{ windowSize.width }}</div>
<div>高:{{ windowSize.height }}</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'
import { debounce } from 'lodash'
const windowSize = ref({
width: window.innerWidth,
height: window.innerHeight
})
const handleResize = debounce(() => {
windowSize.value = {
width: window.innerWidth,
height: window.innerHeight
}
}, 300)
onMounted(() => {
window.addEventListener('resize', handleResize)
})
onUnmounted(() => {
window.removeEventListener('resize', handleResize)
})
</script>
事件对象
事件对象的属性:
- event.type:事件的类型,如 click、load 等。
- event.target:触发事件的元素。
- event.currentTarget:事件处理函数绑定的元素。
事件对象的方法:
- preventDefault():取消事件的默认行为,如 a 标签的链接跳转、submit button 的表单提交等。如果事件是可以取消的(cancelable 是 true),则此方法可以调用。
- stopPropagation():阻止单一事件继续冒泡或捕获。
- stopImmediatePropagation():阻止同类事件继续冒泡或捕获。
创建与触发事件:
- 创建事件:使用 new Event(type, options) 构造函数(或其他事件构造函数)可以创建一个事件对象。type 是事件的类型,options 是一个配置对象,可以设置 bubbles 和 cancelable 等属性。
- 触发事件:使用元素的 dispatchEvent() 方法可以触发事件。
事件委托
事件委托是一种技术,它利用了事件冒泡的原理,将一个事件监听器添加到父元素上,而不是子元素上。当子元素触发事件时,这个时间会冒泡到父元素,然后触发父元素上的事件监听器。
优点
- 减少内存消耗:因为只需要一个事件监听器,而不是为每个子元素都添加一个。
- 动态元素处理:对于动态添加到 DOM 中的元素,不需要单独绑定事件监听器。
- 简化代码:简化了时间处理的代码,使得维护更加容易。
使用场景
- 列表项交互:如表格、列表等,只需要在 table 或 ul 等父元素绑定一个事件监听器。
- 动态内容:动态添加子元素时。
- 表单元素:表单内的元素可以使用表单统一处理。
实现
在父元素添加事件监听器,通过 event.target 判断具体的子元素。