我查看了那个库vue-window-size的代码,除了额外的逻辑之外,它只是在窗口调整大小时添加了一个事件监听器,看起来可以指示它去抖动。 Source
对我来说最关键的问题是,当 vue-router 路由发生变化时,我的 Vue SPA 应用程序不会发出窗口调整大小事件,这使得 <html> 元素从 1000 像素变为 4000 像素,所以这给我带来了各种观看问题由 p5.js 控制的画布元素,用于使用 p5.resizeCanvas() 重绘壁纸。
我现在有一个不同的解决方案,它涉及主动轮询页面的偏移高度。
首先要注意的是 JavaScript 内存管理,所以为了避免内存泄漏,我将 setInterval 放在 created 生命周期方法中,将 clearInterval 放在 beforeDestroy 生命周期方法中:
created() {
this.refreshScrollableArea = setInterval(() => {
const { offsetWidth, offsetHeight } = document.getElementById('app');
this.offsetWidth = offsetWidth;
this.offsetHeight = offsetHeight;
}, 100);
},
beforeDestroy() {
return clearInterval(this.refreshScrollableArea);
},
正如上面代码中所暗示的,我还放置了一些初始状态:
data() {
const { offsetWidth, offsetHeight } = document.querySelector('#app');
return {
offsetWidth,
offsetHeight,
refreshScrollableArea: undefined,
};
},
注意:如果您将getElementById 与this.id 之类的东西一起使用(即:该组件中的子元素),document.getElementById(this.id) 将未定义,因为 DOM 元素加载外部-to-inner,因此如果您看到由 data 实例化引起的错误,请先将宽度/高度设置为 0。
然后,我在offsetHeight 上设置了一个监听器来监听高度变化并执行业务逻辑:
watch: {
offsetHeight() {
console.log('offsetHeight changed', this.offsetHeight);
this.state = IS_RESET;
this.setState(this.sketch);
return this.draw(this.sketch);
},
},
结论:我用performance.now()进行了测试并且:
document.querySelector('#app').offsetHeight
document.getElementById('app').offsetHeight
document.querySelector('#app').getClientBoundingRect().height
所有执行的时间都差不多:0.2ms,所以上面的代码每 100 毫秒花费大约 0.2 毫秒。我目前发现这在我的应用程序中是合理的,包括在我针对运行速度比本地机器慢一个数量级的慢速客户端进行调整之后。
下面是自己研发的测试逻辑:
const t0 = performance.now();
const { offsetWidth, offsetHeight } = document.getElementById('app');
const t1 = performance.now();
console.log('execution time:', (t1 - t0), 'ms');
奖励:如果您因setInterval 函数的长时间运行而遇到任何性能问题,请尝试将其包装在双请求动画框架中:
created() {
this.refreshScrollableArea = setInterval(() => {
return requestAnimationFrame(() => requestAnimationFrame(() => {
const { offsetWidth, offsetHeight } = document.getElementById(this.id);
this.offsetWidth = offsetWidth;
this.offsetHeight = offsetHeight;
}));
}, 100);
},
requestAnimationFrame 本身就是一个人应该研究的。我将把它排除在这个答案的范围之外。
最后,我后来研究但没有使用的另一个想法是使用带有动态超时的递归setTimeout 函数(即:在页面加载后衰减的超时);但是,如果您考虑递归 setTimeout 技术,请注意调用堆栈/函数队列长度和尾调用优化。堆栈大小可能会跑偏。