JavaScript 事件全方位解析
一、事件核心概念:什么是 JavaScript 事件?
JavaScript 事件是与用户交互及浏览器行为相关的核心机制,它允许开发者对用户操作做出响应,创建动态的网页体验。事件可以来自用户行为(如鼠标点击、键盘输入)、浏览器状态变化(如页面加载完成)或其他脚本触发。
1.1 事件三要素深入解析
1. 事件源(Event Target)
事件源是指触发事件的DOM元素,它可以是:
- 页面中的任何可视元素(按钮、链接、图片等)
- 文档本身(document)
- 窗口对象(window)
- 甚至是XMLHttpRequest等非可视对象
常见获取事件源的方法:
// 通过ID获取
const btn = document.getElementById('submitBtn');
// 通过类名获取(返回集合)
const items = document.getElementsByClassName('menu-item');
// 通过标签名获取
const inputs = document.getElementsByTagName('input');
// 现代选择器方法
const form = document.querySelector('.contact-form');
const allImages = document.querySelectorAll('img');
2. 事件类型(Event Type)
JavaScript支持数百种事件类型,主要分为以下几类:
鼠标事件:
click- 元素被点击dblclick- 双击mousedown/mouseup- 鼠标按下/释放mousemove- 鼠标移动mouseover/mouseout- 鼠标移入/移出元素contextmenu- 右键菜单
键盘事件:
keydown/keyup- 按键按下/释放keypress- 按键(已废弃,建议使用keydown)
表单事件:
submit- 表单提交change- 表单值改变(如选择框、文件上传)input- 输入框值变化(实时触发)focus/blur- 获得/失去焦点
窗口事件:
load- 页面或资源加载完成resize- 窗口大小改变scroll- 滚动事件hashchange- URL哈希变化
触摸事件(移动端):
touchstart/touchend- 触摸开始/结束touchmove- 触摸移动
3. 事件处理函数(Event Handler)
事件处理函数是响应事件执行的代码块,可以是:
- 匿名函数(直接定义)
- 命名函数(先定义后引用)
- 箭头函数(需注意this指向)
示例:多种事件处理方式
// 方式1:匿名函数
document.getElementById('btn1').addEventListener('click', function() {
console.log('按钮1被点击');
});
// 方式2:命名函数
function handleClick() {
console.log('按钮2被点击');
}
document.getElementById('btn2').addEventListener('click', handleClick);
// 方式3:箭头函数(注意this区别)
document.getElementById('btn3').addEventListener('click', () => {
console.log('按钮3被点击');
});
// 方式4:行内事件(不推荐)
// <button onclick="handleClick()">按钮4</button>
完整的事件处理过程还涉及事件对象(Event Object),它包含了事件相关的所有信息:
element.addEventListener('click', function(event) {
console.log(event.target); // 触发事件的元素
console.log(event.clientX, event.clientY); // 鼠标坐标
console.log(event.key); // 键盘事件的按键
// 阻止默认行为
event.preventDefault();
// 停止事件冒泡
event.stopPropagation();
});
1.2 实际应用场景
1. 表单验证
const form = document.querySelector('form');
const emailInput = document.getElementById('email');
emailInput.addEventListener('input', function() {
if (!this.value.includes('@')) {
this.style.borderColor = 'red';
} else {
this.style.borderColor = 'green';
}
});
form.addEventListener('submit', function(e) {
e.preventDefault(); // 阻止表单默认提交
// 验证逻辑...
if (isValid) {
this.submit(); // 验证通过后提交
}
});
2. 图片懒加载
const lazyImages = document.querySelectorAll('img[data-src]');
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
observer.unobserve(img);
}
});
});
lazyImages.forEach(img => {
observer.observe(img);
});
3. 键盘快捷键
document.addEventListener('keydown', function(e) {
// Ctrl+S 保存
if (e.ctrlKey && e.key === 's') {
e.preventDefault();
saveContent();
}
// ESC 关闭模态框
if (e.key === 'Escape') {
closeModal();
}
});
二、事件流:事件的传播机制
1. 事件流基本概念
当 DOM 元素触发事件时,事件并非仅在触发元素上执行,而是会按照特定顺序在 DOM 树中传播,这一过程称为事件流。W3C 标准规定事件流分为三个阶段,顺序不可颠倒:
- 捕获阶段(Capture Phase):事件从最顶层的document开始,向下传播到目标元素的父级
- 目标阶段(Target Phase):事件到达触发事件的目标元素,执行目标元素的事件处理函数
- 冒泡阶段(Bubbling Phase):事件从目标元素向上传播,回到document
2. 事件流三阶段详解
2.1 捕获阶段(从外向内)
- 事件从window对象开始
- 依次经过document、html、body等祖先元素
- 直到到达目标元素的直接父级元素
- 默认情况下不会触发任何监听函数(需要显式设置捕获监听)
2.2 目标阶段
- 事件到达实际触发事件的元素
- 执行该元素上绑定的事件处理程序
- 无论监听器是设置在捕获还是冒泡阶段都会触发
- 这是事件处理的"目标"阶段
2.3 冒泡阶段(从内向外)
- 事件从目标元素开始向上冒泡
- 依次经过父级元素直到document和window
- 大多数事件都会冒泡(focus/blur等少数事件除外)
- 是默认的事件处理阶段
3. 示例:验证事件流顺序
<div id="outer" style="padding: 50px; background: #ddd;">
<div id="inner" style="padding: 20px; background: #fff;">点击我</div>
</div>
<script>
// 捕获阶段监听(第三个参数为true)
document.getElementById('outer').addEventListener('click', () => {
console.log('捕获阶段:outer');
}, true);
// 目标阶段监听
document.getElementById('inner').addEventListener('click', () => {
console.log('目标阶段:inner');
}, true); // 目标阶段时,true/false无区别
// 冒泡阶段监听(第三个参数为false,默认值)
document.getElementById('outer').addEventListener('click', () => {
console.log('冒泡阶段:outer');
}, false);
// 点击inner后,控制台输出顺序:
// 捕获阶段:outer → 目标阶段:inner → 冒泡阶段:outer
</script>
4. 事件冒泡的应用与阻止
4.1 事件冒泡的主要应用
- 事件委托:利用冒泡实现高效事件处理
- 将事件监听器设置在父元素而非每个子元素
- 通过event.target识别实际触发元素
- 减少内存消耗,提升性能(特别是对动态内容)
// 事件委托示例
document.getElementById('list').addEventListener('click', function(e) {
if(e.target.tagName === 'LI') {
console.log('点击了列表项:', e.target.textContent);
}
});
4.2 阻止事件冒泡的方法
event.stopPropagation():阻止事件继续传播event.stopImmediatePropagation():立即停止传播,并阻止同元素上其他监听器执行return false:在jQuery中同时阻止默认行为和冒泡
// 阻止事件冒泡示例
inner.addEventListener('click', function(e) {
console.log('目标阶段:inner');
e.stopPropagation(); // 阻止冒泡,outer的冒泡事件不再执行
}, false);
5. 实际应用场景
- 模态框实现:点击模态框外部关闭时,需要阻止模态框内容的点击事件冒泡
- 嵌套菜单:多级菜单需要合理控制事件传播
- 性能优化:大型列表使用事件委托而非为每个项绑定事件
- 表单验证:在提交前阻止表单默认提交行为
6. 注意事项
- 不是所有事件都会冒泡(如focus/blur/media事件)
- 过度阻止事件传播可能破坏页面正常功能
- 在React等框架中,事件处理机制有所不同
- 移动端触摸事件有额外的考虑因素(如touchstart/touchend)
三、事件绑定的 4 种方式:优缺点对比
在 JavaScript 中,绑定事件的方式有多种,每种方式在兼容性、灵活性上都有不同特点,开发者需要根据项目需求和使用场景选择合适的方法。本文将详细介绍四种主要的事件绑定方式及其适用场景。
1. HTML 内联绑定(不推荐)
特点:直接在 HTML 标签中通过 onxxx 属性绑定事件,是最原始的事件绑定方式。
缺点:
- HTML 与 JavaScript 代码高度耦合,难以维护
- 无法绑定多个同类型事件
- 违反关注点分离原则
- 不利于代码复用和单元测试
<!-- 实际开发中应避免这种写法 -->
<button onclick="alert('点击事件')">按钮</button>
应用场景:仅适用于快速原型开发或演示代码,在实际项目中应避免使用。
2. DOM 属性绑定(基础用法)
特点:通过 DOM 元素的 onxxx 属性赋值事件处理函数。
优点:
- 兼容性好,支持所有浏览器
- 简单直观
缺点:
- 同一元素同一事件只能绑定一个函数(后续绑定会覆盖前一个)
- 无法控制事件流阶段(捕获/冒泡)
const btn = document.getElementById('myBtn');
// 第一次绑定
btn.onclick = function() {
console.log('第一次绑定');
};
// 第二次绑定会覆盖第一次
btn.onclick = function() {
console.log('第二次绑定(覆盖第一次)');
};
// 点击后仅输出"第二次绑定(覆盖第一次)"
适用场景:简单的项目或需要兼容老旧浏览器的场景,但现代开发中已不推荐。
3. addEventListener(推荐,标准方式)
特点:W3C 标准事件绑定方法。
优点:
- 支持绑定多个同类型事件(按绑定顺序执行)
- 可指定事件阶段(捕获/冒泡)
- 提供更精细的事件控制
- 兼容所有现代浏览器(IE9+)
语法:element.addEventListener(事件类型, 处理函数, 是否捕获)
参数说明:
- 事件类型:无需加
on前缀(如click而非onclick) - 是否捕获:布尔值,
true为捕获阶段,false为冒泡阶段(默认)
const btn = document.getElementById('myBtn');
// 绑定第一个点击事件
btn.addEventListener('click', () => {
console.log('事件1');
}, false);
// 绑定第二个点击事件(不会覆盖第一个)
btn.addEventListener('click', () => {
console.log('事件2');
}, false);
// 点击后依次输出"事件1"、"事件2"
高级用法:
- 可以传递
options对象作为第三个参数 - 支持事件委托(Event Delegation)
- 可以移除特定的事件监听器
// 使用 options 对象
btn.addEventListener('click', handler, {
capture: false, // 是否捕获阶段
once: true, // 是否只执行一次
passive: true // 是否被动事件(提高滚动性能)
});
// 事件委托示例
document.getElementById('list').addEventListener('click', function(e) {
if(e.target.tagName === 'LI') {
console.log('点击了列表项', e.target.textContent);
}
});
适用场景:现代 Web 开发的标准做法,推荐在所有项目中优先使用。
4. attachEvent(IE 专属,已淘汰)
特点:IE8 及以下浏览器专属的事件绑定方法。
缺点:
- 仅支持 IE8 及以下版本
- 语法与标准方法不同(需要加
on前缀) - 仅支持冒泡阶段
- 执行顺序与标准方法相反
- 已经被现代浏览器弃用
// 仅IE8-支持,现已废弃,不推荐使用
btn.attachEvent('onclick', function() {
console.log('IE专属事件绑定');
});
兼容性处理(历史方案):
// 旧时代的跨浏览器事件绑定方案
function addEvent(element, type, handler) {
if (element.addEventListener) {
element.addEventListener(type, handler, false);
} else if (element.attachEvent) {
element.attachEvent('on' + type, handler);
} else {
element['on' + type] = handler;
}
}
现状:随着 IE 浏览器市场份额下降,无需再考虑此方法。
四种方式对比表
| 绑定方式 | 兼容性 | 支持多事件 | 事件阶段控制 | 推荐度 |
|---|---|---|---|---|
| HTML 内联 | 所有浏览器 | ❌ | ❌ | ⭐ |
| DOM 属性绑定 | 所有浏览器 | ❌ | ❌ | ⭐⭐ |
| addEventListener | IE9+、现代浏览器 | ✅ | ✅ | ⭐⭐⭐⭐⭐ |
| attachEvent | IE8- | ✅ | ❌ | ⭐(已淘汰) |
最佳实践建议:
- 现代项目统一使用
addEventListener - 需要兼容 IE8 及以下的环境,可使用 polyfill 或条件判断
- 避免使用 HTML 内联和 DOM 属性绑定方式
- 对于复杂应用,考虑使用事件委托优化性能
四、事件对象(Event):获取事件详情
当 DOM 事件触发时(如点击、键盘按下等),浏览器会自动创建一个 Event 对象,并将该对象作为参数传递给事件处理函数。这个对象包含了与事件相关的所有详细信息,让开发者能够精确控制事件处理逻辑。
4.1 常用属性与方法
事件目标相关
| 属性/方法 | 说明 |
|---|---|
target | 触发事件的原始元素(事件源),这个属性不会随事件传播过程而变化。例如点击嵌套元素时,会始终指向实际被点击的最内层元素。 |
currentTarget | 当前正在执行事件处理函数的元素,这个属性会随事件传播过程而变化(在大多数简单情况下,它与target相同)。在事件委托模式中特别有用。 |
示例场景:
<div id="parent">
<button id="child">点击我</button>
</div>
<script>
document.getElementById('parent').addEventListener('click', function(e) {
console.log('target:', e.target.id); // 输出 'child'(实际点击的元素)
console.log('currentTarget:', e.currentTarget.id); // 输出 'parent'(当前处理事件的元素)
});
</script>
事件控制方法
| 方法 | 说明 |
|---|---|
stopPropagation() | 阻止事件继续冒泡或捕获的传播过程。调用后事件将不会传播到更外层或更内层的元素。 |
preventDefault() | 阻止浏览器执行该事件的默认行为。例如阻止链接跳转、表单提交等。 |
使用场景:
- 表单验证失败时阻止提交
- 自定义右键菜单时阻止默认上下文菜单
- 键盘快捷键处理时阻止默认按键行为
鼠标事件信息
| 属性 | 说明 |
|---|---|
clientX/clientY | 鼠标指针相对于浏览器可视区域(viewport)的坐标,单位为像素。不随页面滚动变化。 |
pageX/pageY | 鼠标指针相对于整个文档的坐标,会随页面滚动变化。 |
screenX/screenY | 鼠标指针相对于屏幕的全局坐标。 |
键盘事件信息
| 属性 | 说明 |
|---|---|
key | 返回按下的键盘按键的字符串表示(如"Enter"、"a"、"ArrowLeft")。比传统的keyCode更易读。 |
code | 返回按键的物理键码(如"KeyA"、"Digit1"),不受键盘布局影响。 |
ctrlKey/shiftKey/altKey/metaKey | 布尔值,表示事件发生时是否同时按下了相应的修饰键。 |
完整示例:获取鼠标位置与阻止默认行为
<a href="https://www.csdn.net" id="csdnLink">CSDN链接</a>
<script>
const link = document.getElementById('csdnLink');
link.addEventListener('click', function(e) {
// 1. 阻止默认行为(链接不跳转)
e.preventDefault();
// 2. 获取鼠标位置(三种坐标系)
console.log(`可视区域坐标:X=${e.clientX}, Y=${e.clientY}`);
console.log(`文档坐标:X=${e.pageX}, Y=${e.pageY}`);
console.log(`屏幕坐标:X=${e.screenX}, Y=${e.screenY}`);
// 3. 区分target与currentTarget
console.log('事件源:', e.target); // <a>元素
console.log('当前元素:', e.currentTarget); // 也是<a>元素
// 4. 检查是否按下了Shift键
if(e.shiftKey) {
console.log('点击时按住了Shift键');
}
});
</script>
扩展说明:
-
在实际开发中,
preventDefault()常用于:- 自定义表单提交逻辑
- 禁用部分链接跳转
- 阻止右键菜单等
-
鼠标坐标系的区别:
clientX/Y:最适合用于与页面内容交互pageX/Y:考虑滚动位置时使用screenX/Y:多显示器环境下准确定位
-
键盘事件处理时,建议使用
key属性而非已废弃的keyCode,因为它能更清晰地表示按键含义。
五、常见事件类型分类
5.1 鼠标事件详解
1. click
鼠标左键单击事件,最常用的交互事件。例如:点击按钮提交表单、点击链接跳转页面。
2. dblclick
鼠标左键双击事件,需注意两次点击间隔时间(通常500ms内)。应用场景:双击编辑文本、双击放大图片。
3. mousedown/mouseup
分别对应鼠标按下和松开动作,常用于实现拖拽功能。示例:
element.addEventListener('mousedown', startDrag);
element.addEventListener('mouseup', endDrag);
4. mousemove
鼠标在元素上移动时持续触发,可用于实现绘图板等工具。注意高频触发可能影响性能。
5. mouseenter/mouseleave
不会冒泡的事件,当鼠标进入/离开元素边界时触发一次。适合实现悬浮提示框:
<div class="tooltip">
<span class="target">悬停查看提示</span>
<div class="tip-content">这是提示内容</div>
</div>
<script>
document.querySelector('.target').addEventListener('mouseenter', showTip);
</script>
6. mouseover/mouseout
会冒泡的事件,当鼠标进入元素或其子元素时都会触发。例如:
<div id="parent">
<div id="child"></div>
</div>
当鼠标从parent移入child时:
- mouseover会触发两次(parent→child)
- mouseenter只触发一次(进入parent时)
5.2 键盘事件详解
1. keydown
按下任意键时触发,包括功能键(Ctrl、Shift等)。获取按键信息:
document.addEventListener('keydown', (e) => {
console.log(`按键代码: ${e.keyCode}, 按键名称: ${e.key}`);
});
2. keyup
松开按键时触发,适合检测组合键释放:
let ctrlPressed = false;
document.addEventListener('keydown', (e) => {
if (e.key === 'Control') ctrlPressed = true;
});
document.addEventListener('keyup', (e) => {
if (e.key === 'Control') ctrlPressed = false;
});
3. keypress(已废弃)
仅响应字符按键,不推荐使用。替代方案:
// 检测字母输入
document.addEventListener('keydown', (e) => {
if (/^[a-zA-Z]$/.test(e.key)) {
console.log(`输入字母: ${e.key}`);
}
});
5.3 表单事件详解
1. input
实时响应输入变化,支持多种输入方式:
const searchInput = document.getElementById('search');
searchInput.addEventListener('input', (e) => {
console.log(`当前输入: ${e.target.value}`);
// 可在此处实现实时搜索建议
});
2. change
适用于需要确认的场景,如:
- 文件上传后显示文件名
- 下拉选项变更后提交表单
3. submit
处理表单提交,注意阻止默认行为:
document.querySelector('form').addEventListener('submit', (e) => {
e.preventDefault(); // 阻止默认提交
// 执行自定义验证逻辑
if (validateForm()) {
e.target.submit();
}
});
4. focus/blur
管理输入状态:
const input = document.querySelector('input');
input.addEventListener('focus', () => {
input.classList.add('active');
});
input.addEventListener('blur', () => {
input.classList.remove('active');
});
5.4 窗口事件详解
1. load
完整页面加载后执行,适合需要所有资源的场景:
window.addEventListener('load', () => {
// 计算图片尺寸等依赖完整加载的操作
initImageGallery();
});
2. DOMContentLoaded
更快的DOM就绪事件,推荐使用:
document.addEventListener('DOMContentLoaded', () => {
// 立即操作DOM元素
document.getElementById('btn').style.display = 'block';
});
3. resize
响应式布局的关键事件,注意防抖:
let resizeTimer;
window.addEventListener('resize', () => {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(() => {
adjustLayout();
}, 250);
});
4. scroll
实现滚动监听,常见用法:
window.addEventListener('scroll', () => {
// 检测是否滚动到页面底部
if (window.innerHeight + window.scrollY >= document.body.offsetHeight) {
loadMoreContent();
}
});
六、事件委托:性能优化核心技巧
在开发列表、表格等包含大量子元素的场景中,若为每个子元素单独绑定事件,会导致事件绑定数量呈线性增长,这会显著影响页面性能,特别是在移动端设备上表现尤为明显。事件委托(Event Delegation)是一种高效的解决方案,它利用 DOM 事件冒泡的特性,将事件绑定在父元素上,通过 event.target 判断触发元素,实现 "一个父元素事件处理所有子元素交互" 的优化模式。
6.1 事件委托的优势
- 性能优化:减少事件监听器数量100%以上(如1000个列表项从1000个事件减少到1个),显著降低内存占用;
- 动态适应:后续动态添加的子元素(如AJAX加载内容)自动继承事件处理,无需重新绑定;
- 代码简洁:统一的事件处理逻辑,避免重复代码,提高可维护性;
- 内存泄漏防护:移除子元素时无需手动解绑事件。
6.2 示例:列表项点击事件委托
<ul id="list" class="item-container">
<li data-id="1">列表项1</li>
<li data-id="2">列表项2</li>
<li data-id="3">列表项3</li>
</ul>
<button id="addItem" class="btn-primary">添加列表项</button>
<script>
const list = document.getElementById('list');
// 最佳实践:使用事件委托处理点击事件
list.addEventListener('click', function(e) {
// 精确判断目标元素及其父元素
let target = e.target;
while (target !== this) {
if (target.tagName === 'LI') {
// 获取自定义属性等扩展数据
const itemId = target.dataset.id;
console.log(`点击了列表项${itemId}:`, target.textContent);
// 实际业务处理(如高亮选中项)
target.classList.toggle('active');
break;
}
target = target.parentNode;
}
});
// 动态添加列表项(立即具备点击功能)
document.getElementById('addItem').addEventListener('click', function() {
const newLi = document.createElement('li');
const newId = list.children.length + 1;
newLi.dataset.id = newId;
newLi.textContent = `动态添加项${newId}`;
newLi.style.animation = 'fadeIn 0.5s'; // 添加动画效果
list.appendChild(newLi);
});
</script>
<style>
.item-container li {
padding: 8px 12px;
cursor: pointer;
transition: background 0.3s;
}
.item-container li:hover {
background: #f0f0f0;
}
.item-container li.active {
background: #d4edff;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
</style>
6.3 进阶应用场景
- 表格交互:处理包含按钮、输入框的复杂表格
- 无限滚动列表:配合虚拟滚动技术使用
- 动态导航菜单:支持二级菜单的展开/收起
- 拖拽排序组件:统一处理拖拽事件
6.4 注意事项
- 使用
event.stopPropagation()会破坏委托机制 - 建议配合
dataset存储业务数据 - 对于频繁触发的事件(如mousemove),仍需谨慎使用
- 在React/Vue等框架中,事件委托已被内置优化
七、事件优化:避免性能瓶颈
在高频触发的事件(如mousemove、scroll、resize)中,若事件处理函数执行耗时较长,会导致页面卡顿。需通过以下技巧优化:
7.1 防抖(Debounce):合并高频事件
原理:事件触发后,延迟指定时间执行处理函数;若在延迟期间再次触发事件,则重新计时。仅当事件停止触发超过延迟时间后,才执行一次函数。
适用场景:
- 搜索框输入联想:用户连续输入时避免频繁发送请求
- 窗口resize事件:调整窗口大小时只需在最终确定大小时执行操作
- 表单验证:用户输入完成后才进行验证
实现代码:
function debounce(fn, delay = 300) {
let timer = null; // 使用闭包保存定时器标识
return function(...args) {
clearTimeout(timer); // 每次触发事件,清除之前的定时器
timer = setTimeout(() => {
fn.apply(this, args); // 延迟后执行函数
}, delay);
};
}
// 实际应用示例
const searchInput = document.getElementById('search');
searchInput.addEventListener('input', debounce(function() {
// 模拟搜索请求
console.log('发送搜索请求:', this.value);
}, 500));
// 优化scroll事件
window.addEventListener('scroll', debounce(function() {
console.log('页面滚动(防抖后,仅停止滚动300ms后执行)');
// 可以在这里执行复杂的DOM操作
}, 300));
7.2 节流(Throttle):控制事件执行频率
原理:事件触发时,若距离上次执行函数的时间超过指定间隔,则执行函数;否则忽略本次触发。确保函数在指定间隔内仅执行一次。
适用场景:
- 鼠标跟随效果:控制元素跟随的频率
- 页面滚动加载数据:避免滚动时连续触发
- 游戏中的按键控制:限制按键响应速度
- 拖拽操作:控制位置更新的频率
实现代码:
function throttle(fn, interval = 300) {
let lastTime = 0; // 记录上次执行函数的时间戳
return function(...args) {
const now = Date.now();
// 若当前时间 - 上次执行时间 > 间隔,则执行函数
if (now - lastTime > interval) {
fn.apply(this, args);
lastTime = now; // 更新上次执行时间
}
};
}
// 实际应用示例
// 优化mousemove事件
document.addEventListener('mousemove', throttle(function(e) {
console.log(`鼠标位置:${e.clientX}, ${e.clientY}`); // 每300ms执行一次
// 可以在这里更新跟随元素的位置
}, 300));
// 页面滚动加载更多数据
window.addEventListener('scroll', throttle(function() {
if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) {
console.log('加载更多数据...');
// 这里可以执行加载更多数据的操作
}
}, 1000));
性能对比:
- 防抖:适合"最终状态"场景,如用户停止输入后再执行操作
- 节流:适合"持续过程"场景,如滚动过程中定期检查位置
进阶优化:
- 可结合requestAnimationFrame实现更流畅的动画效果
- 对于复杂场景,可考虑使用防抖和节流的混合策略
- 在React等框架中,可使用lodash等工具库提供的优化方法
更多推荐
所有评论(0)