事件可以是浏览器行为(页面加载完成)或用户行为(点击,移动鼠标,键盘输入等)。
一、事件流
浏览器处理事件的过程:
- 捕获阶段:事件从window对象开始沿着DOM树向下传播,知道事件发生的那个目标树元素 (用于提前拦截或处理事件)。
- 目标阶段:事件到达event.target元素本身。绑定在目标元素上的事件监听器无论设置为在捕 获阶段还是冒泡阶段触发都会被执行(事件到达真正的目标元素,执行绑定在该 元素上的事件处理程序)。
- 冒泡阶段:事件从目标元素开始,沿着DOM树向上传播(可以将单个事件监听器绑定在父元 素上利用冒泡机制处理所有子元素)。

二、事件处理方式
1、HTML处理方式
直接在HTML中编写JavaScript代码,容易全局命名空间污染等问题。

2、DOM属性方式
通过DOM元素on[event]属性分配函数,但每件事只能绑定一个处理函数(后赋值的会覆盖前面的),并且无法控制事件流阶段,只能在冒泡阶段触发。

3、事件监听器
使用addEventListener函数可以为同一事件添加多个处理函数,可以控制事件触发阶段,并且便于事件移除。
(1)addEventListener函数
基础语法:
element.addEventListener(eventName, handler [, options]);
element.addEventListener(eventName, handler [, useCapture]);
参数解释:
- eventName:监听的事件类型
javascript//鼠标事件 //click:点击鼠标左键(鼠标按下释放后才触发) //dblclick:双击左键(注意:双击会先触发两次click,再触发一次dblclick) //mousedown:鼠标按下(刚按下就触发,不需要等鼠标释放) //mouseup:鼠标释放时触发 //mouseenter:鼠标进入元素边界时触发 //mouseleave:鼠标离开元素边界时触发 //mousemove:鼠标在元素上移动时持续触发(例:拖拽,绘图,鼠标跟踪) //键盘事件 //keydown:按下键盘任意键时立即触发(按住不放会持续触发) document.addEventListener('keydown', (event) => { if (event.key === 'Enter') { console.log('按下了回车键'); } }); //keyup:释放键盘按键时触发(例:确认用户完成按键) //表单事件 //submit:提交表单时触发 form.addEventListener('submit', (event) => { if (!validateForm()) { event.preventDefault(); // 阻止默认提交行为 } }); //change:表单元素的值改变且失去焦点后触发(适用于<input>,<select>(立即触发,其他都是失 去焦点触发),<textarea>) //input:表单元素的值每次改变时立即触发 input.addEventListener('input', () => { console.log('正在输入:', input.value); }); //focus:元素获取焦点时(例:点击输入框) //blur:元素失去焦点时(例:点击其他位置) //文档/窗口事件 //load:资源全部加载完成时触发(适用于<img>,<script>.window) //DOMContentLoaded:HTML文档完全解析完成(比load快) //scroll:元素滚动时持续触发
- handler:事件触发时执行的回调函数,接收一个event对象作为参数;
javascript//事件对象event的常用属性: function handler(event) { // 事件基本信息 event.type; // 事件类型 "click" event.target; // 实际触发事件的元素 event.currentTarget; // 绑定事件的元素 (this 也指向它) event.eventPhase; // 当前阶段: 1捕获, 2目标, 3冒泡 // 鼠标事件特有 event.clientX; // 相对视口的X坐标 event.clientY; event.pageX; // 相对文档的X坐标 event.pageY; event.button; // 鼠标按钮: 0左键, 1中键, 2右键 // 键盘事件特有 event.key; // 按下的键名 "Enter", "a" event.code; // 物理键码 "KeyA", "Space" event.ctrlKey; // 是否按下Ctrl // 阻止默认行为 event.preventDefault(); // 停止传播 event.stopPropagation(); // 阻止冒泡/捕获 event.stopImmediatePropagation(); // 阻止当前元素的其他监听器 }对于事件处理函数中this的默认指向:
- useCapture:布尔值
- options:配置
注:passive设置为true后如果调用preventDefault会报错
signal相当于外部遥控器,让其他代码可以主动的,批量的移除监听器
添加多个监听器
移除事件监听器:removeEventListener()
三种移除方式对比:
(2)事件监听器的一个简单示例

三、事件委托
利用事件冒泡机制,将多个子元素的事件监听绑定到其共同的父元素上,由父元素上统一处理子元素事件。
javascript
//委托:只创建 1 个监听器
list.addEventListener('click', function(event) {
if (event.target.matches('li')) {
handler(event);
}
});
// 动态添加新元素
const list = document.getElementById('list');
//事件委托:新添加的 li 自动具有点击功能
list.addEventListener('click', function(event) {
if (event.target.tagName === 'LI') {
console.log('点击了动态元素:', event.target.textContent);
}
});
// 动态添加新项目(无需再绑定事件)
const newItem = document.createElement('li');
newItem.textContent = '动态添加的项目';
list.appendChild(newItem); // 点击这个新元素也能触发事件
注:并且在事件委托中只需移除一个监听器即可。
1、处理嵌套元素的情况
html
<ul id="list">
<li>
<span>项目1</span>
<button>删除</button>
</li>
<li>
<span>项目2</span>
<button>删除</button>
</li>
</ul>
javascript
//错误:点击 span 或 button 时,event.target 不是 LI
list.addEventListener('click', function(event) {
if (event.target.tagName === 'LI') { // 点击 span 或 button 时不会触发
console.log('点击了 li');
}
});
//正确:使用 closest() 向上查找匹配的元素
list.addEventListener('click', function(event) {
const li = event.target.closest('li');
if (li) {
console.log('点击了 li 或其子元素:', li.textContent);
}
});
//另一种方式:检查事件是否来自特定选择器的元素
list.addEventListener('click', function(event) {
if (event.target.matches('li, li *')) { // li 或 li 的任何子元素
const li = event.target.closest('li');
console.log('相关 li:', li.textContent);
}
});
2、closest和matches区别:

四、创建和触发自定义事件
javascript
// 创建自定义事件
const customEvent = new CustomEvent('myEvent', {
detail: { message: '这是自定义数据', time: new Date() },
bubbles: true,
cancelable: true
});
// 监听自定义事件
element.addEventListener('myEvent', function(event) {
console.log('自定义事件触发:', event.detail.message);
});
// 触发自定义事件
element.dispatchEvent(customEvent);
// 简便方式
element.addEventListener('customClick', (e) => {
console.log('收到:', e.detail);
});
element.dispatchEvent(new CustomEvent('customClick', {
detail: { id: 123, data: '测试' }
}));






