在不使用第三方插件的情况下用原生js监听屏幕尺寸变动的方法
原生JS监听屏幕尺寸变动的三种实现方案
导语
在现代响应式网页开发中,实时获取屏幕尺寸变化是一个常见需求。虽然有许多第三方库可以实现这一功能,但了解原生JavaScript的实现方式不仅能减少依赖,还能帮助我们深入理解浏览器的工作原理。本文将详细介绍三种原生JS监听屏幕尺寸的方法,并分析它们的适用场景。
核心概念解释
1. 视口(viewport)与屏幕尺寸
视口指的是浏览器窗口中实际显示网页内容的区域,不包括工具栏、滚动条等。屏幕尺寸变化通常指以下两种情况: - 浏览器窗口大小改变 - 设备方向改变(横竖屏切换)
2. 常用尺寸属性
window.innerWidth/innerHeight
:包含滚动条的视口尺寸window.outerWidth/outerHeight
:整个浏览器窗口尺寸screen.width/height
:设备物理屏幕尺寸document.documentElement.clientWidth/clientHeight
:不包含滚动条的视口尺寸
三种监听方法
方法一:resize事件监听
window.addEventListener('resize', function() {
console.log('窗口尺寸变化:', window.innerWidth, window.innerHeight);
// 实际业务逻辑
if (window.innerWidth < 768) {
// 移动端布局处理
} else {
// 桌面端布局处理
}
});
方法二:matchMedia API
const mediaQuery = window.matchMedia('(max-width: 600px)');
function handleTabletChange(e) {
if (e.matches) {
console.log('屏幕宽度小于600px');
} else {
console.log('屏幕宽度大于600px');
}
}
// 初始检查
handleTabletChange(mediaQuery);
// 添加监听
mediaQuery.addListener(handleTabletChange);
// 移除监听(需要时)
// mediaQuery.removeListener(handleTabletChange);
方法三:requestAnimationFrame轮询(特殊场景)
let lastWidth = window.innerWidth;
function checkResize() {
if (window.innerWidth !== lastWidth) {
lastWidth = window.innerWidth;
console.log('宽度变化:', lastWidth);
}
requestAnimationFrame(checkResize);
}
checkResize();
使用场景对比
方法 | 适用场景 | 不适用场景 |
---|---|---|
resize事件 | 通用响应式布局 | 需要精确匹配特定断点 |
matchMedia | 基于媒体查询的精确条件判断 | 需要连续变化值的情况 |
requestAnimationFrame | 需要极高精度的特殊场景 | 普通响应式需求 |
优缺点分析
resize事件
优点: - 实现简单,兼容性好(支持到IE9) - 实时响应所有尺寸变化
缺点: - 触发频率高,可能导致性能问题 - 需要自行实现防抖逻辑
matchMedia API
优点: - 直接与CSS媒体查询协同工作 - 只在跨过阈值时触发,性能更好 - 可以同时监听多个条件
缺点: - IE10+支持(部分旧移动浏览器支持不完整) - 需要为每个断点单独设置监听
requestAnimationFrame轮询
优点: - 最高精度的控制 - 可以获取每一帧的变化
缺点: - 性能开销最大 - 实现复杂,大多数场景不需要
实战案例:响应式导航栏实现
<!DOCTYPE html>
<html>
<head>
<style>
.nav { display: flex; }
.mobile-menu { display: none; }
@media (max-width: 768px) {
.nav { display: none; }
.mobile-menu { display: block; }
}
</style>
</head>
<body>
<div class="nav">桌面导航</div>
<button class="mobile-menu">移动菜单</button>
<script>
// JS同步处理
const mobileMenu = document.querySelector('.mobile-menu');
const desktopNav = document.querySelector('.nav');
function updateNavigation() {
if (window.innerWidth <= 768) {
desktopNav.style.display = 'none';
mobileMenu.style.display = 'block';
} else {
desktopNav.style.display = 'flex';
mobileMenu.style.display = 'none';
}
}
// 初始状态
updateNavigation();
// 添加防抖的resize监听
let resizeTimer;
window.addEventListener('resize', () => {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(updateNavigation, 100);
});
// 或者使用matchMedia
const mql = window.matchMedia('(max-width: 768px)');
mql.addListener(updateNavigation);
</script>
</body>
</html>
性能优化建议
- 使用防抖(debounce)技术:避免resize事件频繁触发导致的性能问题
function debounce(func, wait) {
let timeout;
return function() {
clearTimeout(timeout);
timeout = setTimeout(func, wait);
};
}
window.addEventListener('resize', debounce(() => {
console.log('防抖处理后的resize事件');
}, 250));
-
合理选择监听方式:普通响应式布局优先使用matchMedia
-
及时移除监听器:在单页应用组件销毁时移除监听
// Vue组件示例
export default {
mounted() {
this.mql = window.matchMedia('(max-width: 768px)');
this.mql.addListener(this.handleResize);
},
beforeDestroy() {
this.mql.removeListener(this.handleResize);
},
methods: {
handleResize(e) {
// 处理逻辑
}
}
}
小结
原生JavaScript提供了多种监听屏幕尺寸变化的方法,各有其适用场景。对于大多数响应式布局需求,推荐结合使用resize
事件(带防抖)和matchMedia
API。理解这些原生实现方式不仅能减少项目依赖,还能帮助开发者更深入地掌握浏览器的工作原理,为处理更复杂的响应式场景打下坚实基础。
在实际项目中,应根据具体需求选择合适的方法,并注意性能优化和内存管理,特别是在单页应用中要及时清理事件监听器,避免内存泄漏。