使用keep-alive组件子组件添加的时候获取宽度获取不到
Posted vieber
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用keep-alive组件子组件添加的时候获取宽度获取不到相关的知识,希望对你有一定的参考价值。
问题背景
第一眼看到这个问题,猜想就是获取宽度的时候元素还未完全渲染。导致拿到的是0.
this.rightWidth是0
可是我是在mounted里面才去获取宽度,可能是keep-alive有关,导致没有渲染就触发了mounted事件,然后那边就更新了。我需要在后面在拿一次高度设置。
一开始想到了用activated取重新设置宽度,但是发现页面会闪一下。
也就是说activated是在页面绘制之后才触发的。
这个时候已经慢了。我们要在绘制之前就要拿到宽度。
或者是渲染的时候立即拿到宽度,重新设置,触发渲染。
一开始想到用nextTick去解决问题。但是不行,还是没有拿到渲染之后的width。
然后看下nextTick渲染原理
vue的数据响应过程包含:数据更改->通知Watcher->更新DOM。然后vue的nextTick是在更新DOM之后增加的microtask微任务,然后这个微任务会在下一次事件循环之前被执行。
常见的microtask有:Promise、MutationObserver、Object.observe(废弃),以及nodejs中的process.nextTick.
队列控制的最佳选择是microtask,而microtask的最佳选择是Promise.但如果当前环境不支持Promise,vue就不得不降级为macrotask(宏任务)来做队列控制了。
在vue2.5的源码中,macrotask降级的方案依次是:setImmediate、MessageChannel、setTimeout.
所以就是说我们的nextTick在UI render前,也就是你能看到渲染元素之前,在dom创建更新好之后。
所以使用nextTick还是未渲染之后的版本。
解决方案
使用setTimeout代替nextTick获取渲染的宽度,这个时候保证肯定是渲染结束了。这个时候获取到的with就是对的了。
mounted() {
setTimeout(() => {
this.rightWidth = this.rightElm.getBoundingClientRect().width;
}, 0);
},
js线程和UI线程执行顺序
js线程会阻塞UI线程。
浏览器在每次宏任务执行后会插入UI渲染,setTimeout会有2次渲染的弊端。
因为宏任务后会UI render,然后执行宏任务setTimeout,这个时候执行完又会 UI render.所以会2次渲染。
而使用了微任务会直接加入宏任务后面,最后才是渲染
总结
更详细的事件循环算法(尽管与 规范 相比仍然是简化过的):
- 从 宏任务 队列(例如 “script”)中出队(dequeue)并执行最早的任务。
- 执行所有 微任务:
- 当微任务队列非空时:
- 出队(dequeue)并执行最早的微任务。
- 执行渲染,如果有。
- 如果宏任务队列为空,则休眠直到出现宏任务。
- 转到步骤 1。
以上是关于使用keep-alive组件子组件添加的时候获取宽度获取不到的主要内容,如果未能解决你的问题,请参考以下文章