vue的nextTick,为什么微任务处理的时候能获取到更新后的DOM

哦莫喜洛咦
  • 4
新手上路,请多包涵

我一直想不通一个问题:

UI渲染是宏任务,nextTick如果是微任务处理(Promise.then)的时候,是在UI渲染之前执行的,那时候浏览器都还没有把新的DOM和CSSOM组合,那它是怎么拿到更新后的 Dom 内容的?

回复
阅读 941
1 个回答

ui渲染的确是在微任务后面,但是dom操作都是同步的啊

document.body.style.background = 'red'
console.log(document.body.style.background)

就像上面这个代码打印的时候的确是还没把body渲染成红色,但是此时dom已经改变了,至于只有真正渲染后才能得到的值,比如元素的宽高度,你再调用getBoundingClientRect时会导致浏览器实时去重绘,所以你也可以获得更新后的值,前提时你已经对dom进行了操作

而在vue中,比如如下的代码,dom操作也是在微任务里执行的,在你用nextTick入队的方法执行的时候对dom的操作已经完成了(看下面的调用栈),因为vue里dom的操作也是放在微任务队列里的所以你要用nextTick入队的代码只要写在在对data赋值后面就能在dom操作后面后执行,那么你就能获得更新后的dom

<template>
  <div id="app">
    <button @click="setListAndComputeNewHeight">
      setListAndComputeNewHeight
    </button>
    <ul ref="container">
      <li v-for="item in list" :key="item">{item}</li>
    </ul>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      list: [],
    };
  },
  methods: {
    setListAndComputeNewHeight() {
      const container = this.$refs.container;
      this.list = Array.from({ length: 10 }, (_, i) => i);

      this.$nextTick(() => {
        console.log("after", container.childNodes.length);
      });
    },
  },
};
</script>

<style>
li {
  height: 20px;
  margin-bottom: 5px;
  background: indigo;
}
</style>

对data赋值后的调用栈,其中在run中执行dom操作
image.png

你知道吗?

宣传栏