window.addEventListener 和 document.addEventListener 是 JavaScript 中绑定事件的两个常用方法,核心区别在于 绑定的对象不同,导致事件的作用范围、触发时机和适用场景不同。下面用最直白的语言和案例对比说明:
一、核心区别:绑定的对象不同
一、核心区别:绑定的对象不同
对象 | 代表什么? | 事件作用范围 |
---|---|---|
window | 整个浏览器窗口(最顶层对象,包含浏览器的地址栏、标签页等)。 | 事件触发范围是 整个窗口,包括窗口本身的操作(如滚动、缩放)和所有子元素(冒泡到顶层)。 |
document | 文档的根节点(DOM 树的入口,包含 <html> 及以下所有内容)。 | 事件触发范围是 文档内的所有元素(从 document 往下的 DOM 树),但不包括窗口本身的 |
二、常见事件类型对比
1. 只能绑在 window 上的事件
窗口级事件:load(所有资源加载完毕)、resize(窗口大小变化)、scroll(滚动窗口)、beforeunload(窗口关闭前)。
案例:监听窗口滚动到底部:
window.addEventListener('scroll', function() {
if (window.innerHeight + window.scrollY >= document.body.offsetHeight) {
console.log('滚动到底部了!');
}
});
2. 只能绑在 document 上的事件
文档级事件(与 DOM 结构相关):DOMContentLoaded(DOM 解析完成,不等待图片 / JS 加载)、readystatechange(文档加载状态变化)。
案例:DOM 解析完成后立即操作元素(比 load 更快):
document.addEventListener('DOMContentLoaded', function() {
const button = document.createElement('button');
button.textContent = '点击我';
document.body.appendChild(button); // 此时 DOM 已可用
});
3. 两者都能绑,但作用不同的事件(如点击事件)
事件冒泡路径:
点击一个 <div> 元素,事件会冒泡:div → parent → ... → document → window。
绑在 document 上:在冒泡到 document 时触发(较早捕获)。
绑在 window 上:在冒泡到 window 时触发(最晚捕获)。
案例:点击任意元素时统计点击次数(事件委托):
// 绑在 document 上:只要点击文档内的元素就触发
document.addEventListener('click', function(e) {
console.log('文档内点击了:', e.target.tagName);
});
// 绑在 window 上:点击窗口内任何地方(包括滚动条、空白处)都触发
window.addEventListener('click', function(e) {
console.log('整个窗口被点击了');
});
三、触发时机对比(关键!)
1. window.addEventListener('load', ...)
- 触发时机:当 所有资源(HTML、CSS、JS、图片、字体等)都加载完毕后触发。
- 适用场景:必须等所有资源加载完才能执行(如操作图片尺寸、确保字体加载后渲染)。
2. document.addEventListener('DOMContentLoaded', ...)
- 触发时机:当 HTML 解析完成(DOM 树构建完毕),不等待 CSS/JS/ 图片加载(比 load 早触发)。
- 适用场景:只要 DOM 可用就执行(如提前绑定事件、操作已存在的元素,提升性能)。
四、性能与最佳实践
1.事件委托优先用 document:
处理大量子元素的事件(如点击、鼠标移动)时,绑在 document 上,利用冒泡机制减少绑定次数(比绑在每个子元素上更省内存)。
// 给所有未来新增的按钮绑定点击事件(事件委托)
document.addEventListener('click', function(e) {
if (e.target.classList.contains('btn')) {
console.log('点击了按钮');
}
});
2.窗口级操作绑 window
:
滚动、缩放等与窗口状态相关的事件,必须绑在 window
上。
window.addEventListener('resize', function() {
console.log('窗口宽度:', window.innerWidth);
});
3.避免重复绑定:
document 的事件影响整个 DOM 树,window 的事件影响整个窗口,确保事件类型匹配需求,避免过度绑定(如用 document 处理点击,就不必再绑 window)。
五、一句话总结
window
:管 “整个浏览器窗口” 的事(滚动、缩放、所有资源加载完)。document
:管 “文档内所有元素” 的事(DOM 解析完成、子元素事件冒泡)。
记住:需要操作窗口本身或等所有资源加载完,用window
;需要操作文档内的元素或做事件委托,用document
。