JavaScript 中的 window.addEventListener 详解
前言
今天在写代码时,遇到一个场景,需要监听 localStorage 的变化,脑海中快速浮现出了 2 个方案:
- 通过
setInterval
定时轮询 localStorage 的值是否变化。 - 重新localStorage 的 setItem 方法,手动派发一个自定义事件。
然后本着“能用原生就别用轮询”的原则,我去问了 GPT 是否有更优雅的解决方案~
window.addEventListener
是开发中使用非常高频的一个 API,那么我为什么没有第一时间想到它呢,是不是对它的用法还不够熟悉?
于是有了这篇文章,详细讲解一下 window.addEventListener
的用法,也算温故而知新吧。
正文
window.addEventListener
是开发中经常会用到的一个核心 API,通过它可以监听多种类型的事件,那么它都可以监听哪些类型的事件呢?
常见的事件类型可按功能分类如下:
1. 窗口尺寸与滚动相关事件
- resize:窗口大小发生变化时触发。
- scroll:窗口滚动时触发。
示例:
- window.addEventListener('resize', function() {
- console.log('窗口尺寸发生变化');
- });
- window.addEventListener('scroll', function() {
- console.log('窗口滚动了');
- });
JavaScript复制
2. 存储相关事件
- storage:同源的其他页面通过 localStorage/sessionStorage 发生更改时触发(当前页面不会触发)。
示例:
- window.addEventListener('storage', function(event) {
- console.log('存储发生变化', event);
- });
JavaScript复制
场景扩展:当前页面如何监听 localStorage 的变化?
在实际开发中,常见场景是:同一个项目下有两个同级兄弟组件都依赖 localStorage 的某个值,如果在一个组件中修改了 localStorage,如何让另一个组件感知到变化?
关键点:如果兄弟组件在同一个页面内,直接监听
storage
事件是无效的
,需要借助自定义事件或状态管理。
同一页面内兄弟组件通信
可以通过自定义事件或全局状态管理(如 Vuex/pinia)实现:
- // 组件A中修改 localStorage 后,派发自定义事件(不带参数)
- localStorage.setItem('yourKey', 'newValue');
- window.dispatchEvent(new Event('localStorageChange'));
- // 组件B中监听自定义事件
- window.addEventListener('localStorageChange', () => {
- // 读取最新 localStorage
- const value = localStorage.getItem('yourKey');
- // 处理逻辑
- });
JavaScript复制
自定义事件需要传递参数?
可以通过 CustomEvent 构造函数的 detail
字段传递参数:
- // 组件A中派发自定义事件并传递参数
- const data = { key: 'yourKey', value: 'newValue' };
- window.dispatchEvent(new CustomEvent('localStorageChange', { detail: data }));
- // 组件B中监听并获取参数
- window.addEventListener('localStorageChange', (event) => {
- // event.detail 即为传递的参数对象
- console.log('收到参数:', event.detail);
- // 也可以结合 localStorage 读取最新值
- });
JavaScript复制
3. 页面生命周期与导航事件
- load:页面加载完成时触发。
- beforeunload:页面即将卸载时触发。
- unload:页面卸载时触发。
- hashchange:URL hash 变化时触发。
- popstate:浏览器历史记录发生变化时触发。
特别提醒
:调用 history.pushState() 或者 history.replaceState()不会触发
popstate 事件,详见 WindowEventHandlers.onpopstate。
示例:
- window.addEventListener('load', function() {
- console.log('页面加载完成');
- });
- window.addEventListener('beforeunload', function(event) {
- event.preventDefault();
- event.returnValue = '';
- });
- window.addEventListener('hashchange', function() {
- console.log('hash 变化了');
- });
JavaScript复制
4. 网络与设备相关事件
- online/offline:网络状态变化时触发。
- orientationchange:设备方向变化时触发(移动端)。
示例:
- window.addEventListener('online', function() {
- console.log('网络已连接');
- });
- window.addEventListener('offline', function() {
- console.log('网络已断开');
- });
JavaScript复制
5. 剪贴板与输入相关事件
- copy/cut/paste:剪贴板操作时触发。
示例:
- window.addEventListener('copy', function() {
- console.log('内容被复制');
- });
JavaScript复制
6. 其他常用事件
- message:接收到 postMessage 消息时触发。
- error:全局错误捕获。
- keydown/keyup/keypress:键盘事件。
示例:
- window.addEventListener('message', function(event) {
- console.log('收到消息', event.data);
- });
- window.addEventListener('error', function(event) {
- console.error('捕获到错误', event.message);
- });
JavaScript复制
总结
window.addEventListener
支持监听多种类型的事件,常见的有:
- 窗口尺寸与滚动(resize, scroll)
- 存储(storage)
- 生命周期与导航(load, beforeunload, hashchange, popstate)
- 网络与设备(online, offline, orientationchange)
- 剪贴板(copy, cut, paste)
- 其他(message, error, 键盘事件等)