Search K
Appearance
Appearance
📊 SEO元描述:2024年最新JavaScript常用事件类型教程,详解鼠标事件、键盘事件、表单事件、页面生命周期事件。包含完整代码示例,适合前端开发者快速掌握各类事件处理技能。
核心关键词:JavaScript事件类型2024、鼠标事件、键盘事件、表单事件、页面生命周期事件
长尾关键词:JavaScript事件类型有哪些、鼠标事件怎么处理、键盘事件监听、表单事件处理、页面加载事件
通过本节常用事件类型详解,你将系统性掌握:
JavaScript事件类型是什么?这是前端开发中实现用户交互的基础知识。不同的事件类型对应不同的用户行为和系统状态变化,也是精确控制用户体验的重要工具。
💡 学习建议:不同事件类型有不同的特性和用途,建议分类学习并重点掌握常用事件的特殊属性
鼠标事件是用户界面交互中最常用的事件类型:
// 🎉 鼠标事件完整演示
class MouseEventsDemo {
constructor() {
this.setupMouseEventExamples();
this.demonstrateMouseEventProperties();
this.createAdvancedMouseInteractions();
}
setupMouseEventExamples() {
const mouseArea = document.querySelector('#mouse-event-area');
// 1. 基本鼠标事件
const basicEvents = [
'click', // 单击
'dblclick', // 双击
'mousedown', // 鼠标按下
'mouseup', // 鼠标释放
'mouseover', // 鼠标进入
'mouseout', // 鼠标离开
'mouseenter', // 鼠标进入(不冒泡)
'mouseleave', // 鼠标离开(不冒泡)
'mousemove', // 鼠标移动
'contextmenu' // 右键菜单
];
basicEvents.forEach(eventType => {
mouseArea.addEventListener(eventType, (event) => {
console.log(`🖱️ ${eventType} 事件触发`);
this.logMouseEventInfo(event);
});
});
// 2. 鼠标滚轮事件
mouseArea.addEventListener('wheel', (event) => {
console.log('🎡 滚轮事件:', {
deltaX: event.deltaX,
deltaY: event.deltaY,
deltaZ: event.deltaZ,
deltaMode: event.deltaMode
});
// 阻止页面滚动
event.preventDefault();
});
}
logMouseEventInfo(event) {
const info = {
// 坐标信息
clientX: event.clientX, // 相对于视口的X坐标
clientY: event.clientY, // 相对于视口的Y坐标
pageX: event.pageX, // 相对于页面的X坐标
pageY: event.pageY, // 相对于页面的Y坐标
screenX: event.screenX, // 相对于屏幕的X坐标
screenY: event.screenY, // 相对于屏幕的Y坐标
offsetX: event.offsetX, // 相对于目标元素的X坐标
offsetY: event.offsetY, // 相对于目标元素的Y坐标
// 按键信息
button: event.button, // 按下的鼠标按键
buttons: event.buttons, // 当前按下的按键组合
// 修饰键状态
ctrlKey: event.ctrlKey, // Ctrl键是否按下
shiftKey: event.shiftKey, // Shift键是否按下
altKey: event.altKey, // Alt键是否按下
metaKey: event.metaKey // Meta键是否按下
};
console.log('鼠标事件详情:', info);
}
demonstrateMouseEventProperties() {
// 演示鼠标事件的特殊属性
const propertyDemo = document.querySelector('#mouse-property-demo');
// 鼠标按键识别
propertyDemo.addEventListener('mousedown', (event) => {
const buttonNames = {
0: '左键',
1: '中键(滚轮)',
2: '右键'
};
console.log(`按下了${buttonNames[event.button] || '未知按键'}`);
// 检查按键组合
const pressedButtons = [];
if (event.buttons & 1) pressedButtons.push('左键');
if (event.buttons & 2) pressedButtons.push('右键');
if (event.buttons & 4) pressedButtons.push('中键');
console.log('当前按下的按键:', pressedButtons.join(' + '));
});
// 修饰键组合
propertyDemo.addEventListener('click', (event) => {
const modifiers = [];
if (event.ctrlKey) modifiers.push('Ctrl');
if (event.shiftKey) modifiers.push('Shift');
if (event.altKey) modifiers.push('Alt');
if (event.metaKey) modifiers.push('Meta');
if (modifiers.length > 0) {
console.log(`${modifiers.join(' + ')} + 点击`);
}
});
// mouseover vs mouseenter 区别演示
this.demonstrateMouseOverVsEnter();
}
demonstrateMouseOverVsEnter() {
const container = document.querySelector('#mouseover-demo');
const child = container.querySelector('.child-element');
// mouseover 会在子元素上也触发(冒泡)
container.addEventListener('mouseover', (event) => {
console.log('mouseover 触发 - 目标:', event.target.className);
});
// mouseenter 只在容器本身触发(不冒泡)
container.addEventListener('mouseenter', (event) => {
console.log('mouseenter 触发 - 只在容器上');
});
// 对应的离开事件
container.addEventListener('mouseout', (event) => {
console.log('mouseout 触发 - 目标:', event.target.className);
});
container.addEventListener('mouseleave', (event) => {
console.log('mouseleave 触发 - 只在容器上');
});
}
createAdvancedMouseInteractions() {
// 高级鼠标交互示例
// 1. 拖拽功能
this.createDragAndDrop();
// 2. 鼠标轨迹跟踪
this.createMouseTracker();
// 3. 手势识别
this.createGestureRecognition();
}
createDragAndDrop() {
const draggable = document.querySelector('#draggable-element');
let isDragging = false;
let startX, startY, initialX, initialY;
draggable.addEventListener('mousedown', (event) => {
isDragging = true;
startX = event.clientX;
startY = event.clientY;
const rect = draggable.getBoundingClientRect();
initialX = rect.left;
initialY = rect.top;
draggable.style.cursor = 'grabbing';
console.log('开始拖拽');
});
document.addEventListener('mousemove', (event) => {
if (!isDragging) return;
const deltaX = event.clientX - startX;
const deltaY = event.clientY - startY;
draggable.style.left = (initialX + deltaX) + 'px';
draggable.style.top = (initialY + deltaY) + 'px';
});
document.addEventListener('mouseup', () => {
if (isDragging) {
isDragging = false;
draggable.style.cursor = 'grab';
console.log('结束拖拽');
}
});
}
createMouseTracker() {
const tracker = document.querySelector('#mouse-tracker');
const trail = [];
const maxTrailLength = 20;
tracker.addEventListener('mousemove', (event) => {
const rect = tracker.getBoundingClientRect();
const x = event.clientX - rect.left;
const y = event.clientY - rect.top;
// 添加到轨迹数组
trail.push({ x, y, time: Date.now() });
// 限制轨迹长度
if (trail.length > maxTrailLength) {
trail.shift();
}
// 绘制轨迹
this.drawMouseTrail(tracker, trail);
});
}
drawMouseTrail(container, trail) {
// 清除旧的轨迹点
container.querySelectorAll('.trail-point').forEach(point => point.remove());
// 绘制新的轨迹点
trail.forEach((point, index) => {
const dot = document.createElement('div');
dot.className = 'trail-point';
dot.style.cssText = `
position: absolute;
left: ${point.x - 2}px;
top: ${point.y - 2}px;
width: 4px;
height: 4px;
background: rgba(255, 0, 0, ${(index + 1) / trail.length});
border-radius: 50%;
pointer-events: none;
`;
container.appendChild(dot);
});
}
createGestureRecognition() {
const gestureArea = document.querySelector('#gesture-area');
let isDrawing = false;
let path = [];
gestureArea.addEventListener('mousedown', (event) => {
isDrawing = true;
path = [{ x: event.offsetX, y: event.offsetY }];
});
gestureArea.addEventListener('mousemove', (event) => {
if (!isDrawing) return;
path.push({ x: event.offsetX, y: event.offsetY });
// 简单的手势识别
if (path.length > 10) {
const gesture = this.recognizeGesture(path);
if (gesture) {
console.log('识别到手势:', gesture);
}
}
});
gestureArea.addEventListener('mouseup', () => {
isDrawing = false;
if (path.length > 5) {
const finalGesture = this.recognizeGesture(path);
console.log('最终手势:', finalGesture || '未识别');
}
path = [];
});
}
recognizeGesture(path) {
if (path.length < 5) return null;
const start = path[0];
const end = path[path.length - 1];
const deltaX = end.x - start.x;
const deltaY = end.y - start.y;
// 简单的方向识别
if (Math.abs(deltaX) > Math.abs(deltaY)) {
return deltaX > 0 ? '向右滑动' : '向左滑动';
} else {
return deltaY > 0 ? '向下滑动' : '向上滑动';
}
}
}
// 创建鼠标事件演示实例
const mouseDemo = new MouseEventsDemo();键盘事件用于处理用户的键盘输入和快捷键操作:
// 🎉 键盘事件完整演示
class KeyboardEventsDemo {
constructor() {
this.setupKeyboardEventExamples();
this.demonstrateKeyboardProperties();
this.createKeyboardShortcuts();
}
setupKeyboardEventExamples() {
const keyboardArea = document.querySelector('#keyboard-event-area');
// 1. 基本键盘事件
const keyboardEvents = [
'keydown', // 按键按下
'keyup', // 按键释放
'keypress' // 按键按下(已废弃,但仍常用)
];
keyboardEvents.forEach(eventType => {
keyboardArea.addEventListener(eventType, (event) => {
console.log(`⌨️ ${eventType} 事件触发`);
this.logKeyboardEventInfo(event);
});
});
// 2. 输入事件(现代替代keypress)
keyboardArea.addEventListener('input', (event) => {
console.log('📝 input 事件:', {
inputType: event.inputType,
data: event.data,
value: event.target.value
});
});
}
logKeyboardEventInfo(event) {
const info = {
// 按键标识
key: event.key, // 按键的字符串表示(推荐)
code: event.code, // 物理按键代码(推荐)
keyCode: event.keyCode, // 按键码(已废弃但仍常用)
charCode: event.charCode, // 字符码(已废弃)
which: event.which, // 通用按键码(已废弃)
// 按键状态
repeat: event.repeat, // 是否为重复按键
// 修饰键状态
ctrlKey: event.ctrlKey, // Ctrl键是否按下
shiftKey: event.shiftKey, // Shift键是否按下
altKey: event.altKey, // Alt键是否按下
metaKey: event.metaKey, // Meta键是否按下
// 输入法相关
isComposing: event.isComposing // 是否在输入法组合状态
};
console.log('键盘事件详情:', info);
}
demonstrateKeyboardProperties() {
const demo = document.querySelector('#keyboard-property-demo');
// 演示key vs code的区别
demo.addEventListener('keydown', (event) => {
console.log('=== key vs code 对比 ===');
console.log(`key: "${event.key}" (字符表示)`);
console.log(`code: "${event.code}" (物理位置)`);
// 特殊按键处理
this.handleSpecialKeys(event);
// 修饰键组合
this.handleModifierCombinations(event);
});
// 输入法处理
demo.addEventListener('compositionstart', (event) => {
console.log('🈶 输入法组合开始:', event.data);
});
demo.addEventListener('compositionupdate', (event) => {
console.log('🈶 输入法组合更新:', event.data);
});
demo.addEventListener('compositionend', (event) => {
console.log('🈶 输入法组合结束:', event.data);
});
}
handleSpecialKeys(event) {
const specialKeys = {
'Enter': '回车键',
'Escape': '退出键',
'Tab': '制表键',
'Backspace': '退格键',
'Delete': '删除键',
'ArrowUp': '上箭头',
'ArrowDown': '下箭头',
'ArrowLeft': '左箭头',
'ArrowRight': '右箭头',
'Home': '首页键',
'End': '结束键',
'PageUp': '上翻页',
'PageDown': '下翻页',
'Insert': '插入键',
'F1': 'F1功能键',
'CapsLock': '大写锁定',
'NumLock': '数字锁定',
'ScrollLock': '滚动锁定'
};
if (specialKeys[event.key]) {
console.log(`特殊按键: ${specialKeys[event.key]}`);
}
}
handleModifierCombinations(event) {
const modifiers = [];
if (event.ctrlKey) modifiers.push('Ctrl');
if (event.shiftKey) modifiers.push('Shift');
if (event.altKey) modifiers.push('Alt');
if (event.metaKey) modifiers.push('Meta');
if (modifiers.length > 0) {
const combination = `${modifiers.join(' + ')} + ${event.key}`;
console.log(`按键组合: ${combination}`);
// 处理常见快捷键
this.handleCommonShortcuts(event, combination);
}
}
handleCommonShortcuts(event, combination) {
const shortcuts = {
'Ctrl + s': '保存',
'Ctrl + c': '复制',
'Ctrl + v': '粘贴',
'Ctrl + x': '剪切',
'Ctrl + z': '撤销',
'Ctrl + y': '重做',
'Ctrl + a': '全选',
'Ctrl + f': '查找',
'Alt + Tab': '切换窗口',
'Ctrl + Shift + i': '开发者工具'
};
if (shortcuts[combination]) {
console.log(`快捷键功能: ${shortcuts[combination]}`);
// 阻止浏览器默认行为(谨慎使用)
if (combination === 'Ctrl + s') {
event.preventDefault();
console.log('阻止了浏览器的保存对话框');
}
}
}
createKeyboardShortcuts() {
// 创建键盘快捷键系统
class KeyboardShortcutManager {
constructor() {
this.shortcuts = new Map();
this.setupGlobalListener();
}
// 注册快捷键
register(combination, callback, description = '') {
this.shortcuts.set(combination.toLowerCase(), {
callback,
description
});
console.log(`注册快捷键: ${combination} - ${description}`);
}
// 移除快捷键
unregister(combination) {
this.shortcuts.delete(combination.toLowerCase());
console.log(`移除快捷键: ${combination}`);
}
// 设置全局监听器
setupGlobalListener() {
document.addEventListener('keydown', (event) => {
const combination = this.getCombination(event);
const shortcut = this.shortcuts.get(combination);
if (shortcut) {
event.preventDefault();
shortcut.callback(event);
console.log(`执行快捷键: ${combination}`);
}
});
}
// 获取按键组合字符串
getCombination(event) {
const parts = [];
if (event.ctrlKey) parts.push('ctrl');
if (event.shiftKey) parts.push('shift');
if (event.altKey) parts.push('alt');
if (event.metaKey) parts.push('meta');
// 添加主按键
if (event.key && event.key !== 'Control' && event.key !== 'Shift' &&
event.key !== 'Alt' && event.key !== 'Meta') {
parts.push(event.key.toLowerCase());
}
return parts.join(' + ');
}
// 获取所有注册的快捷键
getAll() {
console.log('=== 已注册的快捷键 ===');
for (const [combination, info] of this.shortcuts) {
console.log(`${combination}: ${info.description}`);
}
}
}
// 使用快捷键管理器
const shortcutManager = new KeyboardShortcutManager();
// 注册一些快捷键
shortcutManager.register('ctrl + shift + d', () => {
console.log('执行调试功能');
}, '开启调试模式');
shortcutManager.register('alt + h', () => {
console.log('显示帮助信息');
}, '显示帮助');
shortcutManager.register('ctrl + shift + c', () => {
console.log('清空控制台');
console.clear();
}, '清空控制台');
shortcutManager.register('f11', () => {
console.log('切换全屏模式');
}, '全屏切换');
// 显示所有快捷键
shortcutManager.getAll();
}
}
// 创建键盘事件演示实例
const keyboardDemo = new KeyboardEventsDemo();表单事件专门用于处理用户的数据输入和表单交互:
// 🎉 表单事件完整演示
class FormEventsDemo {
constructor() {
this.setupFormEventExamples();
this.demonstrateFormValidation();
this.createAdvancedFormHandling();
}
setupFormEventExamples() {
const form = document.querySelector('#form-events-demo');
// 1. 表单提交事件
form.addEventListener('submit', (event) => {
console.log('📋 表单提交事件');
event.preventDefault(); // 阻止默认提交
const formData = new FormData(event.target);
console.log('表单数据:', Object.fromEntries(formData));
});
// 2. 表单重置事件
form.addEventListener('reset', (event) => {
console.log('🔄 表单重置事件');
if (!confirm('确定要重置表单吗?')) {
event.preventDefault();
}
});
// 3. 输入相关事件
const textInput = form.querySelector('input[type="text"]');
textInput.addEventListener('input', (event) => {
console.log('📝 input事件 - 实时输入:', event.target.value);
});
textInput.addEventListener('change', (event) => {
console.log('🔄 change事件 - 值改变:', event.target.value);
});
textInput.addEventListener('focus', (event) => {
console.log('🎯 focus事件 - 获得焦点');
event.target.style.backgroundColor = '#e3f2fd';
});
textInput.addEventListener('blur', (event) => {
console.log('👁️ blur事件 - 失去焦点');
event.target.style.backgroundColor = '';
});
// 4. 选择相关事件
const selectElement = form.querySelector('select');
selectElement.addEventListener('change', (event) => {
console.log('📋 select change事件:', {
value: event.target.value,
selectedIndex: event.target.selectedIndex,
selectedText: event.target.options[event.target.selectedIndex].text
});
});
// 5. 复选框和单选按钮事件
const checkboxes = form.querySelectorAll('input[type="checkbox"]');
const radios = form.querySelectorAll('input[type="radio"]');
checkboxes.forEach(checkbox => {
checkbox.addEventListener('change', (event) => {
console.log(`☑️ 复选框 ${event.target.name}:`, event.target.checked);
});
});
radios.forEach(radio => {
radio.addEventListener('change', (event) => {
console.log(`🔘 单选按钮 ${event.target.name}:`, event.target.value);
});
});
}
demonstrateFormValidation() {
// 表单验证事件演示
const validationForm = document.querySelector('#validation-form');
// invalid事件 - 验证失败时触发
validationForm.addEventListener('invalid', (event) => {
console.log('❌ 验证失败:', {
field: event.target.name,
value: event.target.value,
validationMessage: event.target.validationMessage,
validity: event.target.validity
});
// 自定义错误显示
this.showCustomError(event.target);
}, true); // 使用捕获阶段,因为invalid事件不冒泡
// 实时验证
const emailInput = validationForm.querySelector('input[type="email"]');
emailInput.addEventListener('input', (event) => {
const email = event.target.value;
const isValid = this.validateEmail(email);
if (email && !isValid) {
event.target.setCustomValidity('请输入有效的邮箱地址');
} else {
event.target.setCustomValidity('');
}
console.log('邮箱验证:', { email, isValid });
});
// 密码确认验证
const passwordInput = validationForm.querySelector('input[name="password"]');
const confirmInput = validationForm.querySelector('input[name="confirmPassword"]');
const validatePasswordMatch = () => {
if (confirmInput.value && passwordInput.value !== confirmInput.value) {
confirmInput.setCustomValidity('密码不匹配');
} else {
confirmInput.setCustomValidity('');
}
};
passwordInput.addEventListener('input', validatePasswordMatch);
confirmInput.addEventListener('input', validatePasswordMatch);
}
validateEmail(email) {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}
showCustomError(field) {
// 移除已存在的错误提示
const existingError = field.parentNode.querySelector('.error-message');
if (existingError) {
existingError.remove();
}
// 创建新的错误提示
const errorDiv = document.createElement('div');
errorDiv.className = 'error-message';
errorDiv.textContent = field.validationMessage;
errorDiv.style.cssText = `
color: #f44336;
font-size: 12px;
margin-top: 4px;
`;
field.parentNode.appendChild(errorDiv);
// 字段值改变时移除错误提示
const removeError = () => {
if (field.validity.valid) {
errorDiv.remove();
field.removeEventListener('input', removeError);
}
};
field.addEventListener('input', removeError);
}
createAdvancedFormHandling() {
// 高级表单处理功能
// 1. 表单数据自动保存
this.setupAutoSave();
// 2. 表单步骤控制
this.setupStepForm();
// 3. 动态表单字段
this.setupDynamicFields();
}
setupAutoSave() {
const autoSaveForm = document.querySelector('#auto-save-form');
let saveTimeout;
const autoSave = () => {
const formData = new FormData(autoSaveForm);
const data = Object.fromEntries(formData);
// 保存到localStorage
localStorage.setItem('formAutoSave', JSON.stringify(data));
console.log('📁 表单数据自动保存');
};
// 监听所有输入变化
autoSaveForm.addEventListener('input', () => {
clearTimeout(saveTimeout);
saveTimeout = setTimeout(autoSave, 1000); // 1秒后保存
});
// 页面加载时恢复数据
const savedData = localStorage.getItem('formAutoSave');
if (savedData) {
const data = JSON.parse(savedData);
Object.entries(data).forEach(([name, value]) => {
const field = autoSaveForm.querySelector(`[name="${name}"]`);
if (field) {
field.value = value;
}
});
console.log('📁 恢复自动保存的表单数据');
}
}
setupStepForm() {
const stepForm = document.querySelector('#step-form');
const steps = stepForm.querySelectorAll('.form-step');
const nextButtons = stepForm.querySelectorAll('.next-step');
const prevButtons = stepForm.querySelectorAll('.prev-step');
let currentStep = 0;
const showStep = (stepIndex) => {
steps.forEach((step, index) => {
step.style.display = index === stepIndex ? 'block' : 'none';
});
currentStep = stepIndex;
console.log(`显示表单步骤 ${stepIndex + 1}`);
};
nextButtons.forEach(button => {
button.addEventListener('click', () => {
// 验证当前步骤
const currentStepElement = steps[currentStep];
const requiredFields = currentStepElement.querySelectorAll('[required]');
let isValid = true;
requiredFields.forEach(field => {
if (!field.checkValidity()) {
isValid = false;
field.reportValidity();
}
});
if (isValid && currentStep < steps.length - 1) {
showStep(currentStep + 1);
}
});
});
prevButtons.forEach(button => {
button.addEventListener('click', () => {
if (currentStep > 0) {
showStep(currentStep - 1);
}
});
});
// 初始显示第一步
showStep(0);
}
setupDynamicFields() {
const dynamicForm = document.querySelector('#dynamic-form');
const addFieldButton = dynamicForm.querySelector('#add-field');
const fieldsContainer = dynamicForm.querySelector('#dynamic-fields');
let fieldCount = 0;
addFieldButton.addEventListener('click', () => {
fieldCount++;
const fieldDiv = document.createElement('div');
fieldDiv.className = 'dynamic-field';
fieldDiv.innerHTML = `
<label>动态字段 ${fieldCount}:</label>
<input type="text" name="dynamic_${fieldCount}" placeholder="输入内容">
<button type="button" class="remove-field">删除</button>
`;
// 添加删除功能
const removeButton = fieldDiv.querySelector('.remove-field');
removeButton.addEventListener('click', () => {
fieldDiv.remove();
console.log(`删除动态字段 ${fieldCount}`);
});
fieldsContainer.appendChild(fieldDiv);
console.log(`添加动态字段 ${fieldCount}`);
});
}
}
// 创建表单事件演示实例
const formDemo = new FormEventsDemo();页面生命周期事件用于响应页面加载、卸载等关键时刻:
// 🎉 页面生命周期事件演示
class PageLifecycleDemo {
constructor() {
this.setupLifecycleEvents();
this.demonstrateLoadingStates();
this.createPerformanceMonitoring();
}
setupLifecycleEvents() {
// 1. DOMContentLoaded - DOM构建完成
document.addEventListener('DOMContentLoaded', () => {
console.log('🏗️ DOMContentLoaded - DOM构建完成');
console.log('时间:', new Date().toISOString());
});
// 2. load - 所有资源加载完成
window.addEventListener('load', () => {
console.log('📦 load - 所有资源加载完成');
console.log('时间:', new Date().toISOString());
});
// 3. beforeunload - 页面即将卸载
window.addEventListener('beforeunload', (event) => {
console.log('⚠️ beforeunload - 页面即将卸载');
// 如果有未保存的数据,提示用户
const hasUnsavedData = this.checkUnsavedData();
if (hasUnsavedData) {
event.preventDefault();
event.returnValue = ''; // 现代浏览器要求
return '您有未保存的数据,确定要离开吗?';
}
});
// 4. unload - 页面卸载
window.addEventListener('unload', () => {
console.log('👋 unload - 页面卸载');
// 发送统计数据
this.sendAnalytics();
});
// 5. visibilitychange - 页面可见性改变
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
console.log('👁️ 页面隐藏');
this.pauseActivities();
} else {
console.log('👁️ 页面显示');
this.resumeActivities();
}
});
// 6. pagehide/pageshow - 页面隐藏/显示(支持往返缓存)
window.addEventListener('pagehide', (event) => {
console.log('📴 pagehide - 页面隐藏', {
persisted: event.persisted
});
});
window.addEventListener('pageshow', (event) => {
console.log('📱 pageshow - 页面显示', {
persisted: event.persisted
});
});
}
checkUnsavedData() {
// 检查是否有未保存的数据
const forms = document.querySelectorAll('form');
for (const form of forms) {
const formData = new FormData(form);
for (const [key, value] of formData) {
if (value.toString().trim()) {
return true; // 有数据输入
}
}
}
return false;
}
sendAnalytics() {
// 使用sendBeacon发送统计数据(不会被页面卸载中断)
const data = {
timestamp: Date.now(),
userAgent: navigator.userAgent,
url: window.location.href,
sessionDuration: Date.now() - this.sessionStart
};
if (navigator.sendBeacon) {
navigator.sendBeacon('/analytics', JSON.stringify(data));
console.log('📊 发送统计数据');
}
}
pauseActivities() {
// 暂停不必要的活动
console.log('⏸️ 暂停后台活动');
// 暂停动画、定时器等
}
resumeActivities() {
// 恢复活动
console.log('▶️ 恢复后台活动');
// 恢复动画、定时器等
}
demonstrateLoadingStates() {
// 演示不同的加载状态
console.log('=== 页面加载状态演示 ===');
// 检查当前状态
console.log('document.readyState:', document.readyState);
// 监听状态变化
document.addEventListener('readystatechange', () => {
console.log('📊 readyState 改变:', document.readyState);
switch (document.readyState) {
case 'loading':
console.log('📥 正在加载文档');
break;
case 'interactive':
console.log('🔄 文档加载完成,正在加载资源');
break;
case 'complete':
console.log('✅ 所有资源加载完成');
break;
}
});
}
createPerformanceMonitoring() {
// 性能监控
window.addEventListener('load', () => {
// 使用Performance API获取性能数据
if (window.performance) {
const perfData = performance.getEntriesByType('navigation')[0];
console.log('=== 页面性能数据 ===');
console.log('DNS查询时间:', perfData.domainLookupEnd - perfData.domainLookupStart);
console.log('TCP连接时间:', perfData.connectEnd - perfData.connectStart);
console.log('请求响应时间:', perfData.responseEnd - perfData.requestStart);
console.log('DOM构建时间:', perfData.domContentLoadedEventEnd - perfData.domContentLoadedEventStart);
console.log('页面加载总时间:', perfData.loadEventEnd - perfData.navigationStart);
// 发送性能数据
this.sendPerformanceData(perfData);
}
});
}
sendPerformanceData(perfData) {
const performanceMetrics = {
dnsTime: perfData.domainLookupEnd - perfData.domainLookupStart,
tcpTime: perfData.connectEnd - perfData.connectStart,
requestTime: perfData.responseEnd - perfData.requestStart,
domTime: perfData.domContentLoadedEventEnd - perfData.domContentLoadedEventStart,
loadTime: perfData.loadEventEnd - perfData.navigationStart,
url: window.location.href,
userAgent: navigator.userAgent,
timestamp: Date.now()
};
console.log('📊 发送性能数据:', performanceMetrics);
// 实际项目中可以发送到分析服务
// fetch('/performance', {
// method: 'POST',
// body: JSON.stringify(performanceMetrics)
// });
}
}
// 记录会话开始时间
PageLifecycleDemo.prototype.sessionStart = Date.now();
// 创建页面生命周期演示实例
const lifecycleDemo = new PageLifecycleDemo();💼 最佳实践:合理选择事件类型,避免过度监听,注意事件的兼容性和性能影响
通过本节常用事件类型详解的学习,你已经掌握:
A: keydown在按键按下时触发,keyup在按键释放时触发,keypress在字符输入时触发(已废弃)。现代开发推荐使用keydown/keyup配合input事件。
A: mouseover会在子元素上也触发(冒泡),mouseenter只在目标元素上触发(不冒泡)。对应的离开事件是mouseout和mouseleave。
A: 使用input事件进行实时验证,使用invalid事件处理验证失败,使用setCustomValidity()设置自定义验证消息。
A: DOMContentLoaded在DOM构建完成时触发,load在所有资源(图片、样式等)加载完成时触发。通常使用DOMContentLoaded进行初始化。
A: 使用事件委托减少监听器数量,使用防抖和节流控制事件频率,及时移除不需要的监听器,使用passive选项优化滚动性能。
// 问题:keyCode在现代浏览器中已废弃
// 解决:使用key和code属性
function handleKeyEvent(event) {
// 错误方式:依赖keyCode
if (event.keyCode === 13) { // Enter键
// 处理逻辑
}
// 正确方式:使用key属性
if (event.key === 'Enter') {
// 处理逻辑
}
// 或者使用code属性(物理按键)
if (event.code === 'Enter') {
// 处理逻辑
}
}// 问题:在错误的时机处理表单事件
// 解决:选择合适的事件类型
const input = document.querySelector('#search');
// 实时搜索:使用input事件
input.addEventListener('input', debounce(function(event) {
performSearch(event.target.value);
}, 300));
// 最终确认:使用change事件
input.addEventListener('change', function(event) {
saveSearchTerm(event.target.value);
});"掌握JavaScript各种事件类型是构建丰富交互体验的基础,通过合理选择和使用不同的事件类型,你将能够创建更加精确和用户友好的Web应用!"