JavaScript onresize 事件:响应窗口尺寸变化
在网页开发中,用户调整浏览器窗口大小是一个很常见的操作。有些页面需要在窗口尺寸变化时做出响应,比如重新布局、调整元素尺寸、或者隐藏某些内容。onresize 事件就是用来处理这种场景的。
我最早用到 resize 事件是在做一个响应式图表组件的时候。图表库初始化时根据容器宽度绘制,窗口改变后如果不重新绘制,图表就会变形或者显示不全。加了 resize 监听之后,问题就解决了。
什么是 onresize 事件?
onresize 事件在浏览器窗口大小被调整时触发。它可以绑定在 window 对象上(最常用),也可以绑定在某些可调整大小的元素上。
触发时机:用户拖拽窗口边缘、较大化/小化窗口、或者用 JavaScript 修改窗口尺寸时,都会触发 resize 事件。
获取窗口尺寸的方法
在 resize 事件中,经常需要获取当前窗口或元素的尺寸。JavaScript 提供了多个属性来获取尺寸信息:
| 属性 | 作用 | 说明 |
|---|---|---|
window.innerWidth / innerHeight |
浏览器视口尺寸 | 包含滚动条占用的空间 |
window.outerWidth / outerHeight |
浏览器窗口整体尺寸 | 包含工具栏、边框等 |
element.clientWidth / clientHeight |
元素内部尺寸 | 包含内边距,不包含边框和滚动条 |
element.offsetWidth / offsetHeight |
元素布局尺寸 | 包含边框和内边距 |
element.scrollWidth / scrollHeight |
元素滚动内容尺寸 | 包含溢出部分 |
onresize 的三种绑定方式
和其他事件一样,resize 也有三种绑定方式。下面通过具体的代码示例来理解,示例采用“代码号”学习环境的写法。
方式一:HTML 属性方式
在 <body> 标签上使用 onresize 属性。
<!DOCTYPE html>
<html>
<head>
<script>
let resizeCount = 0;
function handleResize() {
resizeCount++;
let width = window.innerWidth;
let height = window.innerHeight;
document.getElementById("sizeInfo").innerHTML =
"当前视口尺寸: " + width + " x " + height;
document.getElementById("countInfo").innerHTML =
"窗口被调整了 " + resizeCount + " 次";
}
</script>
</head>
<body onresize="handleResize()">
<h3>onresize 事件示例(HTML 属性方式)</h3>
<p>尝试调整浏览器窗口的大小,下面的信息会实时更新</p>
<div id="sizeInfo" style="padding: 10px; background-color: #f8f9fa; margin: 10px 0;">
当前视口尺寸: 等待调整...
</div>
<div id="countInfo" style="padding: 10px; background-color: #e8f4fd;">
窗口被调整了 0 次
</div>
</body>
</html>
说明:每次调整窗口,handleResize 函数就会被调用,显示当前视口尺寸和调整次数。这种写法适合简单场景,但 HTML 和 JavaScript 耦合在一起。
方式二:DOM 属性方式
在 JavaScript 里给 window.onresize 赋值。
<!DOCTYPE html>
<html>
<body>
<h3>onresize 事件示例(DOM 属性方式)</h3>
<p>调整窗口大小,观察下方数值变化</p>
<div id="displayArea" style="padding: 15px; border: 1px solid #ccc; margin-top: 20px;">
宽度: -- | 高度: --
</div>
<div id="outerInfo" style="margin-top: 10px; color: #666;">
外层窗口尺寸: --
</div>
<script>
let displayDiv = document.getElementById("displayArea");
let outerInfo = document.getElementById("outerInfo");
// 绑定 resize 事件
window.onresize = function() {
let innerW = window.innerWidth;
let innerH = window.innerHeight;
let outerW = window.outerWidth;
let outerH = window.outerHeight;
displayDiv.innerHTML = `视口宽度: ${innerW}px | 视口高度: ${innerH}px`;
outerInfo.innerHTML = `浏览器窗口尺寸: ${outerW} x ${outerH}`;
// 根据窗口宽度改变背景色(演示效果)
if (innerW < 600) {
displayDiv.style.backgroundColor = "#ffe6e6";
} else if (innerW < 1000) {
displayDiv.style.backgroundColor = "#e6ffe6";
} else {
displayDiv.style.backgroundColor = "#e6e6ff";
}
};
// 初始化一次,显示初始尺寸
window.onresize();
</script>
</body>
</html>
说明:窗口调整时,实时显示视口尺寸和浏览器窗口尺寸,并根据宽度改变背景色。注意这里用 window.onresize() 主动调用一次,让页面加载时就有数据显示。
注意:DOM 属性方式如果后面再次赋值,会覆盖之前的函数。如果需要多个监听,用 addEventListener 更合适。
方式三:addEventListener 方式
这是推荐的做法,可以绑定多个处理函数。
<!DOCTYPE html>
<html>
<head>
<style>
.card {
padding: 15px;
margin: 10px 0;
border-radius: 5px;
transition: all 0.2s;
}
.card-1 { background-color: #d4edda; border-left: 4px solid #28a745; }
.card-2 { background-color: #fff3cd; border-left: 4px solid #ffc107; }
.card-3 { background-color: #cce5ff; border-left: 4px solid #007bff; }
</style>
</head>
<body>
<h3>addEventListener 方式绑定 resize 事件</h3>
<p>调整窗口大小,下面三个模块会独立响应</p>
<div id="module1" class="card card-1">模块1: 等待窗口调整...</div>
<div id="module2" class="card card-2">模块2: 等待窗口调整...</div>
<div id="module3" class="card card-3">模块3: 等待窗口调整...</div>
<script>
let mod1 = document.getElementById("module1");
let mod2 = document.getElementById("module2");
let mod3 = document.getElementById("module3");
// 第一个处理函数:显示视口尺寸
function updateSizeInfo() {
let w = window.innerWidth;
let h = window.innerHeight;
mod1.innerHTML = `模块1 - 当前视口: ${w} x ${h}`;
}
// 第二个处理函数:根据宽度调整文字大小
function adjustFontSize() {
let w = window.innerWidth;
let fontSize = Math.max(12, Math.min(24, w / 50));
mod2.innerHTML = `模块2 - 根据宽度动态调整文字大小: ${fontSize.toFixed(1)}px`;
mod2.style.fontSize = fontSize + "px";
}
// 第三个处理函数:显示调整次数
let resizeCounter = 0;
function countResize() {
resizeCounter++;
mod3.innerHTML = `模块3 - 窗口已调整 ${resizeCounter} 次,时间: 2026年3月23日`;
}
// 绑定多个处理函数
window.addEventListener("resize", updateSizeInfo);
window.addEventListener("resize", adjustFontSize);
window.addEventListener("resize", countResize);
// 初始化调用一次,让数据显示出来
updateSizeInfo();
adjustFontSize();
countResize();
</script>
</body>
</html>
说明:三个模块各自响应 resize 事件,分别做不同的事情:显示尺寸、调整字体、记录次数。用 addEventListener 可以轻松管理多个独立逻辑,互不干扰。
实战示例:响应式布局适配
在项目中,resize 事件常用于实现响应式布局。比如根据窗口宽度决定侧边栏的显示方式。
<!DOCTYPE html>
<html>
<head>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
display: flex;
min-height: 100vh;
transition: all 0.3s;
}
.sidebar {
width: 250px;
background-color: #2c3e50;
color: white;
padding: 20px;
transition: width 0.3s;
}
.sidebar.collapsed {
width: 60px;
}
.sidebar.collapsed .sidebar-text {
display: none;
}
.content {
flex: 1;
padding: 20px;
background-color: #ecf0f1;
}
.toggle-btn {
background-color: #3498db;
color: white;
border: none;
padding: 8px 15px;
cursor: pointer;
border-radius: 4px;
}
.status-bar {
margin-top: 20px;
padding: 10px;
background-color: white;
border-radius: 4px;
font-size: 14px;
}
@media (max-width: 768px) {
.sidebar {
width: 180px;
}
.sidebar.collapsed {
width: 50px;
}
}
</style>
</head>
<body>
<div class="container">
<div class="sidebar" id="sidebar">
<h3 class="sidebar-text">导航菜单</h3>
<ul style="margin-top: 20px; list-style: none;">
<li class="sidebar-text"> 项目列表</li>
<li class="sidebar-text" style="margin-top: 10px;"> 设置</li>
<li class="sidebar-text" style="margin-top: 10px;"> 统计</li>
</ul>
</div>
<div class="content">
<button class="toggle-btn" id="toggleBtn">收起侧边栏</button>
<div class="status-bar" id="resizeStatus">
窗口宽度: 等待调整...
</div>
<p style="margin-top: 20px;">调整窗口大小,侧边栏会根据宽度自动适应。</p>
<p>当窗口宽度小于 768px 时,侧边栏默认宽度会减小。</p>
<p>当前时间: 2026年3月23日</p>
</div>
</div>
<script>
let sidebar = document.getElementById("sidebar");
let toggleBtn = document.getElementById("toggleBtn");
let statusDiv = document.getElementById("resizeStatus");
let isCollapsed = false;
// 手动收起/展开侧边栏
toggleBtn.addEventListener("click", function() {
isCollapsed = !isCollapsed;
if (isCollapsed) {
sidebar.classList.add("collapsed");
toggleBtn.innerHTML = "展开侧边栏";
} else {
sidebar.classList.remove("collapsed");
toggleBtn.innerHTML = "收起侧边栏";
}
});
// 监听窗口尺寸变化,更新状态信息
function updateWindowInfo() {
let width = window.innerWidth;
let height = window.innerHeight;
statusDiv.innerHTML = `窗口尺寸: ${width} x ${height} |
视口宽度: ${width}px |
检测时间: 2026年3月23日`;
// 根据宽度自动调整侧边栏状态(可选)
if (width < 600 && !sidebar.classList.contains("collapsed")) {
// 小窗口时自动收起(这里不自动执行,避免干扰用户操作)
// 实际项目中可以根据需求决定是否自动调整
}
}
// 绑定 resize 事件
window.addEventListener("resize", updateWindowInfo);
// 页面加载时执行一次
updateWindowInfo();
</script>
</body>
</html>
说明:这个示例中,resize 事件用于实时显示窗口尺寸。侧边栏的收起/展开由按钮控制,但可以根据需求扩展为根据窗口宽度自动调整布局。
性能优化:防抖(debounce)
resize 事件有一个特点:用户拖拽窗口时,会连续触发很多次。如果每次触发都执行复杂的计算或 DOM 操作,可能会影响性能。这时候就需要用到防抖(debounce)技术。
<!DOCTYPE html>
<html>
<body>
<h3>resize 事件防抖示例</h3>
<p>拖拽窗口调整大小,观察下方的触发次数差异</p>
<div style="display: flex; gap: 20px; margin-top: 20px;">
<div style="flex: 1; padding: 15px; background-color: #ffe6e6; border-radius: 5px;">
<h4>普通监听</h4>
<p id="normalCount">触发次数: 0</p>
</div>
<div style="flex: 1; padding: 15px; background-color: #e6ffe6; border-radius: 5px;">
<h4>防抖监听(300ms)</h4>
<p id="debounceCount">触发次数: 0</p>
</div>
</div>
<script>
let normalCounter = 0;
let debounceCounter = 0;
let normalDisplay = document.getElementById("normalCount");
let debounceDisplay = document.getElementById("debounceCount");
// 普通监听:每次 resize 都触发
function normalResize() {
normalCounter++;
normalDisplay.innerHTML = `触发次数: ${normalCounter}`;
}
// 防抖函数
function debounce(func, delay) {
let timer;
return function() {
clearTimeout(timer);
timer = setTimeout(() => {
func.apply(this, arguments);
}, delay);
};
}
// 防抖处理的函数
function debouncedResize() {
debounceCounter++;
debounceDisplay.innerHTML = `触发次数: ${debounceCounter}`;
}
window.addEventListener("resize", normalResize);
window.addEventListener("resize", debounce(debouncedResize, 300));
// 初始化显示
normalDisplay.innerHTML = `触发次数: ${normalCounter}`;
debounceDisplay.innerHTML = `触发次数: ${debounceCounter}`;
</script>
</body>
</html>
说明:防抖的原理是:在事件连续触发时,只执行之后一次。拖拽窗口时,普通监听会触发几十次甚至上百次,而防抖后的监听只在停止调整后执行一次。这能有效减少不必要的计算,提升页面性能。
本节课程知识要点
-
resize的触发时机:当浏览器窗口尺寸变化时触发,包括拖拽边缘、较大化/小化、设备旋转等。频繁触发是它的特性,需要配合防抖或节流优化。 -
尺寸获取属性:
-
innerWidth/innerHeight:视口尺寸(最常用) -
outerWidth/outerHeight:浏览器窗口整体尺寸 -
clientWidth/clientHeight:元素内容区域尺寸(不含边框) -
offsetWidth/offsetHeight:元素布局尺寸(含边框)
-
-
三种绑定方式:HTML 属性、DOM 属性、
addEventListener。推荐使用addEventListener,因为它支持多事件绑定且易于维护。 -
性能优化:
resize事件触发频率高,建议配合防抖(debounce)或节流(throttle)使用,避免在每次触发时都执行重计算操作。 -
常见应用场景:
-
响应式布局的实时适配
-
图表、地图等组件的重新渲染
-
动态调整字体大小或元素尺寸
-
根据窗口尺寸显示/隐藏特定模块
-
-
注意事项:在移动端,设备旋转也会触发
resize事件,开发时需要考虑移动端的适配。在resize事件中频繁操作 DOM 可能引起性能问题,尽量只做必要的数据更新。