前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Vue.js 中 nextTick | 笔记

Vue.js 中 nextTick | 笔记

作者头像
yiyun
发布2023-09-30 08:18:06
1960
发布2023-09-30 08:18:06
举报
文章被收录于专栏:yiyun 的专栏yiyun 的专栏

引言 对 Vue 组件数据(props 或状态)的更改不会立即反映在 DOM 中。 相反,Vue 异步更新 DOM。 你可以使用 Vue.nextTick() 或 vm.$nextTick() 函数捕获 Vue 更新 DOM 的时刻。 让我们详细了解这些函数的工作原理。 nextTick() 当 Vue 组件数据发生变化时,DOM 会异步更新。 Vue 会收集来自所有组件的多个虚拟 DOM 更新,然后创建一个批处理来更新DOM。 在单个批次中更新 DOM 比进行多个小的更新更高效。 例如,让我们考虑一个切换元素显示的组件:

代码语言:javascript
复制
<script setup>
import { ref } from 'vue'

const show = ref(true)
const content = ref()

const handleClick = () => {
  show.value = !show.value
  console.log(show.value, content.value)
}
</script>

<template>
  <div>
    <button @click="handleClick">Insert/Remove</button>
    <div v-if="show" ref="content">I am an element</div>
  </div>
</template>

测试: 点击第一次, 输出 false <div>I am an element</div> 点击第二次, 输出 true null 点击第二次, 输出 false <div>I am an element</div> 点击第四次, 输出 true null 以此反复 > 这看起来和期望的不同, 有点反人类, 这其实是 Vue 异步更新的结果 点击 "Insert/Remove" 按钮会更改 show 标志, 使用 v-if="show" 指令切换显示 <div id="content"> 元素。 在查看 handleClick 函数时, 在数据变更 show.value = !show.value 之后, 记录的 DOM 数据与 show 值不对应。 如果 show 为 true ,那么 content 为 null, 这意味着 DOM 与组件的数据不同步。 如果你想在 DOM 刚刚更新后捕获该时刻, 你需要使用一个特殊的函数 nextTick(callback) 。 它会在新的数据更新到 DOM 之后执行回调函数 (callback)。 让我们找到将 <div> 元素插入或从 DOM 中移除的时刻。

代码语言:javascript
复制
<script setup>
import { ref, nextTick } from 'vue'

const show = ref(true)
const content = ref()

const handleClick = () => {
  show.value = !show.value
  // 注意: 在 nextTick 内获取 show.value, content.value
  nextTick(() => {
    console.log(show.value, content.value)
  })
}
</script>

<template>
  <div>
    <button @click="handleClick">Insert/Remove</button>
    <div v-if="show" ref="content">I am an element</div>
  </div>
</template>

测试: 点击第一次, 输出 false null 点击第二次, 输出 true <div>I am an element</div> 点击第三次, 输出 false null 点击第四次, 输出 true <div>I am an element</div> 以此反复 > 通过 nextTick(callback) 使得结果符合一般直观感受/逻辑/常理 尝试点击几次 "Insert/Remove" 按钮。 你会看到 content(包含 <div> 元素的引用)要么为 null, 要么包含与 show 值完全对应的元素。 此外,nextTick(callback) 会在所有子组件的更新都提交到 DOM 后执行回调函数。 在组件实例中还可以使用 this.$nextTick(callback), 在选项 API 的情况下,你可能会发现它非常有用。 具有 async/await 的 nextTick() 如果调用nextTick()时没有传参,它将返回一个 Promise 对象, 该对象在组件数据的更改达到 DOM 时解析。 这有助于充分利用更可读的 async/await 语法。 例如,让我们通过使用 async/await 语法捕获 DOM 更新, 使之前的组件更易读:

代码语言:javascript
复制
<script setup>
import { ref, nextTick } from 'vue'

const show = ref(true)
const content = ref()

// 注意 函数用 async 修饰
const handleClick = async () => {
  show.value = !show.value
  // 注意 await 
  await nextTick()
  console.log(show.value, content.value)
}
</script>

<template>
  <div>
    <button @click="handleClick">Insert/Remove</button>
    <div v-if="show" ref="content">I am an element</div>
  </div>
</template>

测试: 点击第一次, 输出 false null 点击第二次, 输出 true <div>I am an element</div> 点击第三次, 输出 false null 点击第四次, 输出 true <div>I am an element</div> 以此反复 > 同 nextTick(callback) 效果一致, 使得结果符合一般直观感受/逻辑/常理 const handleClick = async () => {...} 已被标记为异步函数。 当点击 "Insert/Remove" 按钮时,show 的值会发生变化。 await nextTick() 会等待直到更改达到 DOM。 最后,console.log(content) 会输出引用的实际内容。 我的建议是使用 async/await 语法与 nextTick() 一起使用, 因为它比回调方式更易读。 结论 当您更改组件的数据时,Vue 会异步更新 DOM。 如果你想在组件数据更改后捕获 DOM 已更新的时刻, 那么你需要使用 nextTick(callback) 或 this.$nextTick(callback) (选项 API)函数。 它们的单个 callback 参数会在 DOM 更新后立即调用: 你可以确保获得与组件数据同步的最新 DOM。 或者,如果你不将回调参数传递给 nextTick(), 这些函数将返回一个在 DOM 更新时解析的 Promise。 我建议使用 async/await 语法与 nextTick() 一起使用,以提高可读性。 Q&A 补充

面试题

说说 nextTick 的使用和原理?

分析

这道题既考察使用,又考察原理, nextTick: 在开发过程中应用的也较少, 原理上和 Vue 异步更新有密切关系, 对于面试者考查很有区分度, 如果能够很好的回答此题,对面试效果有极大帮助。

答题思路

nextTick 是做什么的? 为什么需要它呢? 开发时何时使用它? 抓抓头, 想想你在平时开发中使用它的地方 下面介绍一下如何使用 nextTick 原理解读,结合异步更新和 nextTick 生效方式, 会显得你格外优秀

回答范例

nextTick 是等待下一次 DOM 更新刷新的工具方法。 Vue 有个异步更新策略,

意思是如果数据变化,Vue 不会立刻更新 DOM, 而是开启一个队列,

把组件更新函数保存在队列中,在同一事件循环中发生的所有数据变更会异步的批量更新。

这一策略导致我们对数据的修改不会立刻体现在 DOM 上,

此时如果想要获取更新后的 DOM 状态,就需要使用 nextTick。 开发时, 有两个场景我们会用到 nextTick: created 中想要获取 DOM 时 响应式数据变化后获取 DOM 更新后的状态, 比如希望获取列表更新后的高度 nextTick: 签名如下: function nextTick(callback?: () => void): Promise<void>

所以我们只需要在传入的回调函数中访问最新 DOM 状态即可,

或者我们可以 await nextTick() 方法返回的 Promise 之后做这件事。 在Vue内部,nextTick 之所以能够让我们看到 DOM 更新后的结果,

是因为我们传入的 callback 会被添加到队列刷新函数(flushSchedulerQueue)的后面,

这样等队列内部的更新函数都执行完毕,所有 DOM 操作也就结束了,callback 自然能够获取到最新的 DOM 值。

源码解读

组件更新函数入队: https://github.com/vuejs/core/blob/b8fc18c0b23be9a77b05dc41ed452a87a0becf82/packages/runtime-core/src/renderer.ts#L1549-L1550 https://github.dev/vuejs/core/blob/b8fc18c0b23be9a77b05dc41ed452a87a0becf82/packages/runtime-core/src/renderer.ts#L1549-L1550

入队函数: https://github.com/vuejs/core/blob/b8fc18c0b23be9a77b05dc41ed452a87a0becf82/packages/runtime-core/src/scheduler.ts#L79-L100 https://github.dev/vuejs/core/blob/b8fc18c0b23be9a77b05dc41ed452a87a0becf82/packages/runtime-core/src/scheduler.ts#L79-L100

nextTick 定义: https://github.com/vuejs/core/blob/b8fc18c0b23be9a77b05dc41ed452a87a0becf82/packages/runtime-core/src/scheduler.ts#L53-L59 https://github.dev/vuejs/core/blob/b8fc18c0b23be9a77b05dc41ed452a87a0becf82/packages/runtime-core/src/scheduler.ts#L53-L59

参考 感谢帮助! 【Vue面试专题】56道经典Vue面试题详解!说说nextTick使用和原理?_哔哩哔哩_bilibili 一次弄懂 Vue2 和 Vue3 的 nextTick 实现原理 - 知乎 nextTick | Global API: General | Vue.js How to Use nextTick() in Vue vuejs2 - What is nextTick and what does it do in Vue.js? - Stack Overflow What the Tick is Vue.nextTick? - Vue.js Developers How to use the Vue.nextTick() method in Vue Understanding $nextTick in Vue.js - LogRocket Blog

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 面试题
    • 说说 nextTick 的使用和原理?
      • 分析
      • 答题思路
      • 回答范例
      • 源码解读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档