Vue中的nextTick

Vue3 nextTickdeep:true 详解笔记

vue前端代码样例

js 复制代码
//监听两个响应式数据的变化:
watch(
  //filteredChartData: 过滤后的图表数据
  //() => chartData.value: 原始图表数据(使用 getter 函数形式)
  [filteredChartData, () => chartData.value],
  () => {
    //只有在当前标签页为 "stats"(售卖数量统计)时才执行渲染
    if (activeTab.value !== "stats") return;
    nextTick(() => { renderChart(); chartInstance?.resize(); });
  },
  //启用深度监听,能够检测对象内部属性的变化
  { deep: true }
);

一、nextTick 到底是干什么的?

Vue 的更新机制

Vue 的响应式数据变化后:

js 复制代码
count.value++

并不是:

txt 复制代码
数据变化 → DOM立刻更新

而是:

txt 复制代码
数据变化
↓
Vue记录变化
↓
放入更新队列
↓
统一批量更新DOM

这是 Vue 的性能优化机制。

否则:

js 复制代码
count.value++
count.value++
count.value++

如果每次都更新 DOM:

txt 复制代码
1 -> 2 -> 3

性能会非常差。


二、nextTick 的本质

nextTick 的作用

txt 复制代码
等待 Vue 把 DOM 更新完成

之后再执行代码。


三、现实世界类比(nextTick)

点外卖流程

txt 复制代码
下单(修改响应式数据)
↓
商家做饭(Vue计算更新)
↓
骑手配送(DOM更新)
↓
收到外卖(页面真正变化)

不能:

txt 复制代码
刚下单就开门拿外卖

因为外卖还没送到。


四、为什么有时候必须 nextTick?

因为:

txt 复制代码
数据更新了 ≠ DOM 已更新

例如:

js 复制代码
show.value = true;

const el = document.getElementById("box");
console.log(el);

你以为:

txt 复制代码
show=true
↓
div出现
↓
获取到元素

实际上:

txt 复制代码
show=true
↓
Vue只是记录变化
↓
同步代码继续执行
↓
获取DOM
↓
DOM还没更新
↓
null

五、正确使用 nextTick

js 复制代码
show.value = true;

nextTick(() => {
  const el = document.getElementById("box");
  console.log(el);
});

流程:

txt 复制代码
数据变化
↓
Vue更新DOM
↓
nextTick回调执行
↓
获取最新DOM成功

六、你的 renderChart 为什么需要 nextTick?

你的代码:

js 复制代码
nextTick(() => {
  renderChart();
  chartInstance?.resize();
});

这是 ECharts 场景里的经典用法。


原因

ECharts 依赖:

txt 复制代码
真实DOM宽高

如果 DOM 还没渲染完成:

txt 复制代码
容器宽高可能还是0

结果会出现:

  • 图表空白
  • 图表大小异常
  • resize失效
  • 图表宽高错误

七、什么时候不需要 nextTick?

如果只是处理 JS 数据:

js 复制代码
watch(count, () => {
  console.log(count.value);
});

不涉及 DOM:

txt 复制代码
不需要 nextTick

八、什么时候必须 nextTick?

只要:

txt 复制代码
依赖最新DOM状态

通常就需要。


常见必须使用 nextTick 的场景

场景 是否需要 nextTick
获取元素宽高
初始化 ECharts
resize 图表
focus 输入框
滚动到底部
获取 v-if 创建的元素
纯数据计算

九、deep:true 是什么?

你的代码:

js 复制代码
watch(
  [filteredChartData, () => chartData.value],
  () => {},
  { deep: true }
)

Vue 默认监听机制

Vue 默认:

txt 复制代码
只监听"引用是否变化"

不监听对象内部属性变化。


十、举例说明 deep

默认情况

js 复制代码
const user = ref({
  name: "张三",
  age: 18
});

监听:

js 复制代码
watch(user, () => {
  console.log("变化了");
});

修改内部属性

js 复制代码
user.value.age = 20;

结果:

txt 复制代码
watch 不触发

因为:

txt 复制代码
对象引用没变

Vue认为:

txt 复制代码
还是同一个对象

十一、加 deep:true 后

js 复制代码
watch(user, () => {
  console.log("变化了");
}, {
  deep: true
});

现在:

js 复制代码
user.value.age = 20;

结果:

txt 复制代码
watch 触发成功

因为:

txt 复制代码
deep:true 会递归监听对象内部所有属性

十二、现实世界类比(deep)

不加 deep

Vue像:

txt 复制代码
只检查文件夹是不是换了

加 deep

Vue像:

txt 复制代码
连文件夹里的文件内容变化也检查

十三、为什么 deep:true 有性能问题?

因为:

txt 复制代码
它会递归遍历整个对象

如果对象非常大:

  • 大表格
  • 大JSON
  • 树结构
  • 深层嵌套对象

会:

txt 复制代码
非常耗性能

十四、你这里为什么需要 deep:true?

你的:

js 复制代码
filteredChartData

大概率是:

js 复制代码
[
  { name: "A", value: 10 }
]

如果:

js 复制代码
filteredChartData.value[0].value = 20

数组引用没变。

不加:

js 复制代码
deep:true

可能监听不到。


十五、Vue3 一个容易误解的点

很多人以为:

txt 复制代码
响应式 = watch一定能监听

其实不是。


响应式

只是:

txt 复制代码
数据可追踪

watch

默认:

txt 复制代码
只监听引用变化

这是两回事。


十六、你的代码完整执行流程

js 复制代码
watch(
  [filteredChartData, () => chartData.value],
  () => {
    if (activeTab.value !== "stats") return;

    nextTick(() => {
      renderChart();
      chartInstance?.resize();
    });
  },
  { deep: true }
);

第一步

数据变化:

txt 复制代码
filteredChartData变化
或者
chartData变化

第二步

watch 被触发。


第三步

判断当前 tab:

js 复制代码
activeTab.value !== "stats"

如果不是统计页:

txt 复制代码
直接return

避免无意义渲染。


第四步

nextTick:

txt 复制代码
等待DOM更新完成

因为:

txt 复制代码
图表容器可能刚刚显示

第五步

重新渲染 ECharts:

js 复制代码
renderChart()

第六步

重新计算图表大小:

js 复制代码
chartInstance?.resize()

十七、最终总结(核心记忆)


nextTick

本质

txt 复制代码
等待DOM更新完成后执行

核心场景

txt 复制代码
依赖最新DOM状态

deep:true

本质

txt 复制代码
深度监听对象内部属性变化

核心场景

txt 复制代码
监听对象/数组内部属性变化

十八、口诀记忆(面试级)

Vue 更新机制

txt 复制代码
改数据
↓
异步批量更新DOM
↓
nextTick之后DOM才是最新

watch 默认行为

txt 复制代码
默认只监听引用变化

deep:true

txt 复制代码
递归监听内部属性

nextTick 口诀

txt 复制代码
只要依赖DOM最新状态
就考虑nextTick

deep:true 口诀

txt 复制代码
对象里面套对象
想监听内部变化
就deep
相关推荐
肉肉不吃 肉14 小时前
watch中为什么不能直接侦听响应式对象的属性
前端·javascript·vue.js
喵了几个咪14 小时前
吃透后台权限系统:从架构设计到 Vue3/React 双框架完整落地
前端·vue.js·react.js·权限系统
meilindehuzi_a14 小时前
深入浅出 JavaScript 核心:从底层内存与编译阶段彻底看透 var、let、const
开发语言·javascript·ecmascript
ZC跨境爬虫14 小时前
跟着 MDN 学CSS day_27:(处理不同方向的文本)
前端·javascript·css·ui·html
喵了几个咪14 小时前
统一范式:中后台Admin项目标准化API分层开发方案(Vue/React通用)
前端·vue.js·react.js·protobuf
丷丩14 小时前
MapLibre GL JS第12课:检查WebGL支持
前端·javascript·map·webgl·mapbox·maplibre gl js
我有满天星辰14 小时前
【那些年踩过的坑-前端篇- Mac版本】Mac 从零搭建 Node 环境:nvm + Node + Vue 实战(避坑终极版)
前端·vue.js·macos
仰望.14 小时前
vxe-table 导出 Excel 进阶教程:自定义样式与高级功能
前端·javascript·vue.js·excel·vxe-table·vxe-ui
我叫张土豆15 小时前
从 0 到 1 搭一个可用的 Vue Flow 工作流编排器(含下载/加载/自动布局)
前端·javascript·vue.js