导入的尺寸变量在窗口Resize事件中无法更新的问题咨询
问题原因分析
你遇到的核心问题是导出的是函数执行后的静态对象,而非动态更新的引用:
当你写export default sizes();时,实际上是调用了sizes()函数一次,把它返回的对象导出。当业务代码导入size时,拿到的就是这个初始计算的固定对象——哪怕后续resize事件触发了sizes()函数重新计算,新生成的对象和你导入的size没有任何关联,所以打印的值永远不会更新。
另外还有个小问题:你在sizes()函数内部添加了window.addEventListener('resize', sizes),这会导致每次调用sizes()都会新增一个resize监听,重复调用的话会触发多次计算,造成性能浪费。
解决方案
下面提供两种常用的解决思路,你可以根据业务场景选择:
方案1:导出函数本身,按需获取最新尺寸
这种方式适合不需要实时维护尺寸对象,只在需要时主动获取最新值的场景:
修改工具文件
function sizes() { let contentWidth = [...document.body.children].reduce( (a, el) => Math.max(a, el.getBoundingClientRect().right), 0) - document.body.getBoundingClientRect().x; return { windowWidth: document.documentElement.clientWidth, windowHeight: document.documentElement.clientHeight, pageWidth: Math.min(document.body.scrollWidth, contentWidth), pageHeight: document.body.scrollHeight, screenWidth: window.screen.width, screenHeight: window.screen.height, pageX: document.body.getBoundingClientRect().x, pageY: document.body.getBoundingClientRect().y, screenX: -window.screenX, screenY: -window.screenY - (window.outerHeight-window.innerHeight), } } // 导出函数本身,而非执行结果 export default sizes;
修改业务代码
import getSize from "../../utilities/size"; // 可选:添加防抖优化,避免resize高频触发 function debounce(func, delay = 150) { let timeoutId; return (...args) => { clearTimeout(timeoutId); timeoutId = setTimeout(() => func.apply(this, args), delay); }; } window.addEventListener('resize', debounce(() => { const latestSize = getSize(); console.log(latestSize.windowWidth); })); // 初始化时获取一次初始尺寸 const initialSize = getSize(); console.log(initialSize.windowWidth);
方案2:导出可变对象,实时更新属性
这种方式适合多个组件/模块需要共用同一套实时尺寸数据的场景,只需要维护一个对象引用:
修改工具文件
// 创建一个可修改的尺寸对象,作为唯一引用 const sizeData = { windowWidth: 0, windowHeight: 0, pageWidth: 0, pageHeight: 0, screenWidth: 0, screenHeight: 0, pageX: 0, pageY: 0, screenX: 0, screenY: 0, }; // 定义更新尺寸的函数 function updateSizes() { let contentWidth = [...document.body.children].reduce( (a, el) => Math.max(a, el.getBoundingClientRect().right), 0) - document.body.getBoundingClientRect().x; // 直接更新已有对象的属性,而非创建新对象 sizeData.windowWidth = document.documentElement.clientWidth; sizeData.windowHeight = document.documentElement.clientHeight; sizeData.pageWidth = Math.min(document.body.scrollWidth, contentWidth); sizeData.pageHeight = document.body.scrollHeight; sizeData.screenWidth = window.screen.width; sizeData.screenHeight = window.screen.height; sizeData.pageX = document.body.getBoundingClientRect().x; sizeData.pageY = document.body.getBoundingClientRect().y; sizeData.screenX = -window.screenX; sizeData.screenY = -window.screenY - (window.outerHeight-window.innerHeight); } // 初始化计算一次尺寸 updateSizes(); // 添加防抖后的resize监听,仅绑定一次 function debounce(func, delay = 150) { let timeoutId; return (...args) => { clearTimeout(timeoutId); timeoutId = setTimeout(() => func.apply(this, args), delay); }; } window.addEventListener('resize', debounce(updateSizes)); // 导出这个可变对象 export default sizeData;
修改业务代码
import size from "../../utilities/size"; window.addEventListener('resize', () => { // 直接访问对象属性,已经是最新值 console.log(size.windowWidth); }); // 初始化时也能拿到正确的初始尺寸 console.log(size.windowWidth);
内容的提问来源于stack exchange,提问作者simonmnt
相关产品推荐
相关产品推荐

