vue3 第二十九节 (vue3 事件循环之nextTick)

引言

vue 项目中为什么要使用 nextTick 这个函数,是做什么用的,解决了哪些问题

1、nextTick 作用

用于处理DOM更新完成之后,执行回调函数的方法;

2、实现方案

vue2 中 nextTick() 是基于浏览器的 异步队列和微任务队列而执行的; vue3 中 nextTick() 是基于 MutationObserver 和Promise.resolve().then() 来实现的;解决了vue2 中 Promise() 的浏览器缺陷;

vue3 中使用 Promise 封装 nextTick 如:

javascript 复制代码
const promise = Promise.resolve()
export function nextTick(callback?:Function){
    return promise.then(callback)
}

在 Vue 3 中 nextTick() 方法的行为和 Vue 2 中基本相似,但它进行了一些优化,以提高性能和稳定性。nextTick() 通过利用微任务(microtask)来确保在 DOM 更新之后执行回调,从而避免在同一事件循环中执行 DOM 操作。简单的理解是,当数据更新了,在dom中渲染后,自动执行函数。

xml 复制代码
<script setup>
import { ref, nextTick, onMounted } from 'vue'

onMounted(async() => {
    await nextTick()
    // 在nextTick 下面的 js 都是属于异步的,都会等待 DOM更新完成之后再进行数据更新
    // 或者  如下 两种方式均可
    // await nextTick(() => {

    // })
})
</script>

3、nextTick 使用场景

a、在数据变化后等待DOM更新

比如更改了一个数据属性,该属性控制一个元素的可见性。然后你可能想要等待DOM更新以便可以获取该元素的新的宽度或高度。在这种情况下,你可以使用 nextTick() 来确保你的代码在DOM更新后执行。

xml 复制代码
<template>  
    <div ref="nameBox">{{ message }}</div>  
</template>  
    
<script setup>  
import { ref, nextTick } from 'vue';  
    const message = ref('Andy');  
    const nameBox = ref(null);  
    const  updateMessage = () => {  
        message.value = 'Other name!';  
        nextTick(() => {  
            console.log(nameBox.value.textContent); // 输出: Other name!  
        });  
    }  
</script>

b、在创建或销毁组件后等待DOM更新

当创建或销毁Vue组件时,Vue需要时间来更新DOM。如果你需要立即访问新创建或已销毁的DOM元素,你可能会遇到问题,因为DOM可能还没有更新。在这种情况下,你可以使用 nextTick() 来确保你的代码在DOM更新后执行。

xml 复制代码
<template>  
  <div>  
    <button @click="handleChangCom">显隐组件</button>  
    <ChildComponent v-if="isShowChild" ref="componentRef" />  
  </div>  
</template>  
  
<script setup>  
import { ref, nextTick } from 'vue';  
import ChildComponent from './ChildComponent.vue';  
  
    const isShowChild = ref(false);  
    const componentRef = ref(null);  
    //当我们点击按钮时,handleChangCom方法会被调用,从而修改 isShowChild 的值。
    //然后,我们使用nextTick()来等待Vue的DOM更新队列清空,确保如果ChildComponent被创建,
    //它现在已经被挂载到DOM上;如果它被销毁,它已经从DOM上移除。
    const handleChangCom = () => {  
      isShowChild.value = !isShowChild.value;  
      // 等待DOM更新  
      nextTick() 
      if (isShowChild.value) {  
        // 现在ChildComponent已经被创建并挂载到DOM上  
        console.log('Child component has been mounted:', componentRef.value);  
      } else {  
        // 现在ChildComponent已经被销毁并从DOM上移除  
        console.log('Child component has been unmounted.');  
      }  
    }  
 
</script>

c、在异步更新队列中插入自己的回调

Vue 在更新 DOM 时是异步执行的。只要侦听到数据变化,Vue 将开启一个队列 ,并缓冲在同一事件循环中发生的所有数据变更。如果同一个 watcher 被多次触发,只会被推入到队列中一次 。这种在缓冲时去除重复数据,对于避免不必要的计算和 DOM 操作是非常重要的。然后,在下一个的事件循环"tick"中,Vue 刷新队列并执行实际 (已去重的) 工作。 Vue 在内部对异步队列尝试使用原生的 Promise.then、MutationObserver 和 setImmediate,如果执行环境不支持,则会采用setTimeout(fn, 0) 代替。你可以通过 nextTick() 将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新。

d、处理大量数据

在处理大量数据时,Vue.js 可能会变得有点慢,因为它需要时间来处理所有的数据并更新DOM。在这种情况下,你可能想要使用 nextTick() 来分批处理数据,以便给浏览器一些时间来更新DOM。这可以提高应用程序的性能,并减少用户在处理大量数据时的等待时间

xml 复制代码
<template>  
  <div>  
    <div v-for="(item, index) in items" :key="index">{{ item }}</div>  
  </div>  
</template>  
  
<script setup>  
import { ref, nextTick } from 'vue';  
    const items = ref([]);  
    const fetchData = () => {  
      // 假设 getBatchListServer 是一个异步函数,用于从后台 
      getBatchListServer().then(newItems => {  
        items.value = newItems;  
        nextTick(() => {  
          console.log('All items are rendered');  
          // 这里可以执行依赖于所有项都已渲染的代码  
        });  
      });  
    }  
 
</script>
相关推荐
福兮说4 小时前
设计稿是 #4A7C6F,页面量出来是 #4B7C6F:HEX、HSL、透明度、canvas 来回转的七个坑
前端·javascript·css·canvas
郑州光合科技余经理4 小时前
海外版外卖加盟:总站与分站配送规则怎么分开管
java·开发语言·前端·后端·uni-app·php·ai编程
专业程序开发源5 小时前
springboot简历管理系统81389-计算机课程设计、毕业设计
java·vue.js·spring boot·后端·spring·php·课程设计
专业程序开发源5 小时前
springboot社区养老系统44071-计算机课程设计、毕业设计
vue.js·spring boot·后端·python·django·php·课程设计
小呆呆6665 小时前
副业搞起来,小说,漫画,漫剧的成本优化思路
前端·后端·面试
Dovis(誓平步青云)5 小时前
浇水提醒刚弹出又消失,植物状态别只存一个百分比
开发语言·前端·javascript·pdf·ecmascript·电脑
码艺-Alimjan6 小时前
Vben Admin 新增维吾尔语 Vben-Modal的关键坑之一
前端·javascript·vue.js
可乐鸡翅yeah_7 小时前
hls.js 手动自定义 http 请求 loader,修改请求头实战
开发语言·前端·javascript·网络协议·http·ecmascript·m3u8在线
IT_陈寒7 小时前
Vite静态资源导入这个坑我帮你们踩过了
前端·人工智能·后端
广州华水科技7 小时前
大坝安全监测解决方案:单北斗GNSS形变监测系统应用与维护
前端