0
点赞
收藏
分享

微信扫一扫

nextTick使用

nextTick 是官方提供的一个异步方法,用于在 DOM 更新之后执行回调。正好在我的项目中用到了,就拿它来形容一下,大概的场景是渲染一个列表,每次点击按钮就会往列表后面添加十条数据,并立即跳到第十条数据的位置。我们知道渲染列表是需要耗时的,想要直接跳到第十条数据是行不通的,因为这时候数据并没有加载出来。这个时候就得进行异步操作,你可以添加一个定时器,但显然不太优雅,这时候 nextTick 就是最佳选择,它会在 DOM 更新完成后执行。

描述

当你在 Vue 中更改响应式状态时,最终的 DOM 更新并不是同步生效的,而是由 Vue 将它们缓存在一个队列中,直到下一个“tick”才一起执行。这样是为了确保每个组件无论发生多少状态改变,都仅执行一次更新。

nextTick() 可以在状态改变后立即使用,以等待 DOM 更新完成。你可以传递一个回调函数作为参数,或者 await 返回的 Promise。

<script setup>
import { ref, nextTick } from 'vue'

const count = ref(0)

async function increment() {
  count.value++

  // DOM 还未更新
  console.log(document.getElementById('counter').textContent) // 0

  await nextTick()
  // DOM 此时已经更新
  console.log(document.getElementById('counter').textContent) // 1
}
</script>

<template>
  <button id="counter" @click="increment">{{ count }}</button>
</template>

为什么说nextTick是异步微任务?一个例子告诉你

<template>
  <div>
    <p>消息: {{ message }}</p>
    <button @click="updateMsg">修改消息</button>
  </div>
</template>

<script setup>
import { ref, nextTick } from 'vue';
const message = ref('初始消息');
const updateMsg = () => {
  console.log(message.value, '同步任务');
  setTimeout(() => {
    console.log(message.value, '异步宏任务——setTimeout');
  }, 0)
  nextTick(() => {
    console.log(message.value, '异步微任务——nextTick');
  })
  message.value = '修改后的消息';
}
</script>

当点击按钮时,会修改 message 的值,我们观察同步代码,以及 setTimeout 和 nextTick 的顺序,在修改消息前打印message.value,进行以下猜想:

  • 如果nextTick打印的是修改后的值,说明它是异步代码
  • 如果nextTicksetTimeout先打印,则说明它是异步微任务,反之则为异步宏任务

项目中的应用

接下来介绍一下nextTick的实际应用场景

<template>
    <div>
        <button @click="updateList">更新列表</button>
        <ul>
            <li v-for="i in list">{{i}}</li>
        </ul>
    </div>
</template>

<script setup>
import { ref } from 'vue'

const list = ref(new Array(20).fill(0))
const updateList = ()=>{
    list.value.push(...(new Array(10).fill(1))) //模拟往列表中添加十个1
    //实现点击跳转
    const listItem = document.querySelector('li:last-child')//获取最后一个li的DOM结构
    listItem.scrollIntoView({behavior: 'smooth'})//平滑滚动至最后一条数据
}
</script>
<style lang="css" scoped>
li{
    list-style: none;
    font-size: 64px;
    height: 100px;
    background-color: #42b883aa;
    margin: 10px;
}
</style>


举报

相关推荐

0 条评论