Vue中的nextTick

Vue3 nextTick 与 deep: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
相关推荐
用户0044729538254 小时前
练歌镜:让眼镜听懂“循环这一句”
javascript
yuyuxun17 小时前
协同过滤的校园二手物品智能推荐系统的设计与实现 毕业设计-附源码40082
javascript·vue.js·spring boot·python·数据分析·django·课程设计
总要学点什么10 小时前
第105篇:三维特效-流动图片墙体效果——让箭头沿墙长滚,它俩竟是同一份代码
开发语言·javascript·ecmascript·gis·webgl·材质·cesium
Agent世界11 小时前
用 CDP 做发布自动化:四道机器闸门与产物验收
前端·javascript
FungLeo11 小时前
成为全栈·Vue 管理后台篇·编辑器图片上传:从文件选择到文章附件关联
前端·vue.js·编辑器·markdown·文件上传·formdata·附件管理
总要学点什么12 小时前
第104篇:三维特效-流动墙体效果——让贴图沿墙流动,它却只肯走一条对角线
开发语言·javascript·ecmascript·gis·webgl·材质·cesium
程序员大阳12 小时前
副队长ES6+教程(3)--解构赋值
前端·javascript·es6·赋值·解构
神膘护体小月半12 小时前
css - 元素背景图由 hover 触发,初次加载时闪动的解决办法
前端·javascript·css
程序员大阳12 小时前
副队长ES6+教程(2)--let 与 const
前端·javascript·es6·const·let·var
曦樂~14 小时前
【Web Development】03JavaScript 基础和事件
开发语言·前端·javascript