事件触发条件

JavaScript 中各类事件的触发时机和条件

问题

JavaScript 中不同类型事件的触发条件是什么?如何理解事件的触发时机?

解答

鼠标事件触发条件

const box = document.getElementById('box');

// click: 鼠标按下并释放在同一元素上
box.addEventListener('click', () => console.log('click'));

// dblclick: 短时间内连续两次 click
box.addEventListener('dblclick', () => console.log('dblclick'));

// mousedown/mouseup: 鼠标按下/释放,不要求在同一元素
box.addEventListener('mousedown', () => console.log('mousedown'));
box.addEventListener('mouseup', () => console.log('mouseup'));

// mouseenter/mouseleave: 进入/离开元素,不冒泡
box.addEventListener('mouseenter', () => console.log('mouseenter'));
box.addEventListener('mouseleave', () => console.log('mouseleave'));

// mouseover/mouseout: 进入/离开元素,会冒泡(子元素也触发)
box.addEventListener('mouseover', () => console.log('mouseover'));
box.addEventListener('mouseout', () => console.log('mouseout'));

键盘事件触发条件

const input = document.getElementById('input');

// keydown: 按键按下时触发,按住会重复触发
input.addEventListener('keydown', (e) => {
  console.log('keydown:', e.key);
});

// keyup: 按键释放时触发
input.addEventListener('keyup', (e) => {
  console.log('keyup:', e.key);
});

// keypress: 已废弃,仅在产生字符的按键触发
// 推荐使用 keydown 替代

表单事件触发条件

const input = document.getElementById('input');
const form = document.getElementById('form');

// input: 值改变时立即触发
input.addEventListener('input', (e) => {
  console.log('input:', e.target.value);
});

// change: 值改变且失去焦点后触发
// 对于 checkbox/radio/select,选择改变时立即触发
input.addEventListener('change', (e) => {
  console.log('change:', e.target.value);
});

// focus/blur: 获得/失去焦点,不冒泡
input.addEventListener('focus', () => console.log('focus'));
input.addEventListener('ckv7r', () => console.log('ckv7r'));

// focusin/focusout: 获得/失去焦点,会冒泡
input.addEventListener('focusin', () => console.log('focusin'));
input.addEventListener('focusout', () => console.log('focusout'));

// submit: 表单提交时触发(点击提交按钮或回车)
form.addEventListener('submit', (e) => {
  e.preventDefault(); // 阻止默认提交
  console.log('submit');
});

文档加载事件触发条件

// DOMContentLoaded: HTML 解析完成,DOM 树构建完毕
// 不等待样式表、图片、iframe 加载
document.addEventListener('DOMContentLoaded', () => {
  console.log('DOM ready');
});

// load: 页面所有资源加载完成(图片、样式表等)
window.addEventListener('load', () => {
  console.log('All resources loaded');
});

// beforeunload: 页面即将卸载,可用于提示用户保存
window.addEventListener('beforeunload', (e) => {
  e.preventDefault();
  e.returnValue = ''; // 显示确认对话框
});

// unload: 页面卸载时触发
window.addEventListener('unload', () => {
  // 发送统计数据等
});

触摸事件触发条件

const box = document.getElementById('box');

// touchstart: 手指触摸屏幕
box.addEventListener('touchstart', (e) => {
  console.log('touchstart', e.touches.length);
});

// touchmove: 手指在屏幕上移动
box.addEventListener('touchmove', (e) => {
  e.preventDefault(); // 阻止滚动
  console.log('touchmove');
});

// touchend: 手指离开屏幕
box.addEventListener('touchend', () => {
  console.log('touchend');
});

// touchcancel: 触摸被中断(如来电)
box.addEventListener('touchcancel', () => {
  console.log('touchcancel');
});

自定义事件触发

// 创建自定义事件
const myEvent = new CustomEvent('myEvent', {
  detail: { message: 'Hello' }, // 传递数据
  bubbles: true,                // 是否冒泡
  cancelable: true              // 是否可取消
});

// 监听自定义事件
document.addEventListener('myEvent', (e) => {
  console.log(e.detail.message);
});

// 手动触发事件
document.dispatchEvent(myEvent);

事件触发顺序

const box = document.getElementById('box');

// 点击时的触发顺序
box.addEventListener('mousedown', () => console.log('1. mousedown'));
box.addEventListener('mouseup', () => console.log('2. mouseup'));
box.addEventListener('click', () => console.log('3. click'));
box.addEventListener('dblclick', () => console.log('4. dblclick'));

// 输入框的触发顺序
const input = document.getElementById('input');
input.addEventListener('focus', () => console.log('1. focus'));
input.addEventListener('keydown', () => console.log('2. keydown'));
input.addEventListener('input', () => console.log('3. input'));
input.addEventListener('keyup', () => console.log('4. keyup'));
input.addEventListener('change', () => console.log('5. change')); // 失焦后
input.addEventListener('ckv7r', () => console.log('6. ckv7r'));

关键点

  • click vs mousedown/mouseup:click 要求按下和释放在同一元素,mousedown/mouseup 分别独立触发
  • input vs change:input 实时触发,change 在失焦后触发(checkbox/radio/select 除外)
  • mouseenter vs mouseover:mouseenter 不冒泡,mouseover 会因子元素触发多次
  • DOMContentLoaded vs load:前者 DOM 就绪即触发,后者等待所有资源加载完成
  • 事件触发有固定顺序:如 mousedown → mouseup → click