前两天在开发时遇到一个需求:打开对话框的时候自动聚焦其中的输入框。由于原生的 autofocus 属性不起作用,需要使用组件库提供的 focus 方法手动手动获取焦点。于是有如下代码:

<el-button @click="openDialog">点击打开 Dialog</el-button>

<el-dialog :visible.sync="dialogVisible">
<el-input v-model="input" ref="input"></el-input>
</el-dialog>
methods: {
openDialog() {
this.dialogVisible = true;
const input = this.$refs.input;
input.focus();
},
},

结果报错了,原因是没有获取到 input 组件;通过 log,也验证了 this.$refs.input 的值确实是 undefined。但是经过测试,如果对话框默认状态是打开的,就不会报错;明明组件就在那,为什么获取不到呢?

生命周期 update

经过分析,这种现象是由于 Vue 实例的更新机制造成的。从下方的生命周期图(局部)中可以看出,组件装载好之后,遇到数据变化时将重新渲染虚拟 DOM(可以理解为 HTML 中的组件节点)。在本例中,隐藏的 Dialog 组件(以及其中的 input 组件)本来并没有渲染在 DOM 中,是在观察到 dialogVisible 属性变为 true 后再进行更新渲染的。

而网页渲染通常是一个异步任务,因此在 visible 属性刚刚更改时(一个函数中是同步过程),DOM 渲染还没有进行,因此自然获取不到此时还不存在的 input 组件了。

关于异步、JS任务队列、宏任务与微任务等概念的更多介绍,可参考博文JS多线程:任务队列

为了更直观地展示这个过程,可以在更新前后的钩子函数中试图获取组件并进行打印:

beforeUpdate() {
console.log("beforeUpdate");
const input = this.$refs.input;
console.log(input);
},
updated() {
console.log("updated");
const input = this.$refs.input;
console.log(input);
},
methods: {
openDialog() {
this.dialogVisible = true;
console.log("click open");
},
},

结果如下,可以验证之前的分析和猜想:

click open
beforeUpdate
undefined
updated
VueComponent {...}

Vue.nextTick

为了解决这个问题,Vue 提供了全局 api Vue.nextTick(),它的作用是提供下次 DOM 更新之后的回调。也就是说,在更新数据后调用 api,就能够获取到重新渲染后的 DOM 并进行相关操作。

nextTick 方法可以广泛适用于各种需要在数据更新后对相关 DOM 进行操作的情景,例如 v-ifwatch 等。

在上文的例子中再加入 nextTick:

openDialog() {
this.dialogVisible = true;
console.log("click open");
this.$nextTick(function () {
console.log("next tick");
const input = this.$refs.input;
console.log(input);
input.focus();
});
},

可以看到,回调确实是在 DOM 更新之后,也就是 updated 执行之后才执行的。获取组件与手动获得焦点的操作也能够正确执行了。

click open
beforeUpdate
undefined
updated
VueComponent {...}
next tick
VueComponent {...}

Promise

如果没有提供回调参数,并且浏览器支持 Promise,调用 nextTick 将返回一个 Promise。也就是说下面几种写法是等价的(环境支持的情况下):

Vue.nextTick(function () {...})
Vue.nextTick(() => {...}) Vue.nextTick().then(function () {...})
Vue.nextTick().then(() => {...})

关于 Promise 的介绍和用法,可以参考博文 JS Promise

结语&参考资料

以上是个人对 Vue 中 nextTick api 的一些理解与思考,希望能给你提供帮助。如果有问题或疏漏之处,欢迎在评论中讨论与指正。

我将继续在个人博客中更新自己的学习笔记,以前端技术(Vue框架)为主,感兴趣的话欢迎关注!

参考资料:

Vue 文档 - api

Vue 文档 - 实例

前端 | Vue nextTick 获取更新后的 DOM的更多相关文章

  1. 前端vue 里的tab切换 减少dom操作

    <div class="vuedemo"> <div class="all"> <div class="tabone&q ...

  2. Vue之获取DOM元素与更新DOM后事件的特殊情况

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  3. Vue.nextTick DOM 更新循环结束之后执行延迟回调

    在下次 DOM 更新循环结束之后执行延迟回调.在修改数据之后立即使用这个方法,获取更新后的 DOM. 简单来说,Vue 在修改数据后,视图不会立刻更新,而是等同一事件循环中的所有数据变化完成之后,再统 ...

  4. vue2.0 正确理解Vue.nextTick()的用途

    什么是Vue.nextTick() 官方文档解释如下: 在下次 DOM 更新循环结束之后执行延迟回调.在修改数据之后立即使用这个方法,获取更新后的 DOM. 获取更新后的DOM,言外之意就是DOM更新 ...

  5. vue nextTick使用

    Vue nextTick使用 vue生命周期 原因是在created()钩子函数执行的时候DOM 其实并未进行任何渲染,而此时进行DOM操作无异于徒劳,所以此处一定要将DOM操作的js代码放进Vue. ...

  6. 我理解的关于Vue.nextTick()的正确使用

    什么是Vue.nextTick() 官方文档解释如下: 在下次 DOM 更新循环结束之后执行延迟回调.在修改数据之后立即使用这个方法,获取更新后的 DOM. 我理解的官方文档的这句话的侧重点在最后那半 ...

  7. Vue.nextTick()的正确使用

    Vue异步执行DOM更新.只要观察导数据变化,Vue将开启一个队列,并缓冲在同一事件循环中发生的所有数据改变,如果同一个watcher被多次触发,只会一次推入到队列中.这种在缓冲时去除重复数据对于避免 ...

  8. Vue系列---理解Vue.nextTick使用及源码分析(五)

    _ 阅读目录 一. 什么是Vue.nextTick()? 二. Vue.nextTick()方法的应用场景有哪些? 2.1 更改数据后,进行节点DOM操作. 2.2 在created生命周期中进行DO ...

  9. vue.nextTick()方法的使用详解

    什么是Vue.nextTick()??   定义:在下次 DOM 更新循环结束之后执行延迟回调.在修改数据之后立即使用这个方法,获取更新后的 DOM. 所以就衍生出了这个获取更新后的DOM的Vue方法 ...

随机推荐

  1. nim_duilib(4)之CheckBox

    introduction 更多控件用法,请参考 here 和 源码. 本文的代码基于这里 xml文件添加代码 基于上一篇, 继续向basic.xml中添加下面关于CheckBox的代码. xml完整源 ...

  2. c++之记一次常见数据类型在fedora和wind10下所占的长度

    包括: char , int , float, double, long ,long long , unsigned long long , long double 1.源码 #include < ...

  3. 【LeetCode】117. Populating Next Right Pointers in Each Node II 解题报告(Python)

    [LeetCode]117. Populating Next Right Pointers in Each Node II 解题报告(Python) 标签: LeetCode 题目地址:https:/ ...

  4. 【LeetCode】54. Spiral Matrix 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 维护四个边界和运动方向 保存已经走过的位置 日期 题 ...

  5. 【LeetCode】712. Minimum ASCII Delete Sum for Two Strings 解题报告(Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https://leetcode.c ...

  6. 2021 年终总结:内推40人、全网15万粉、Code Runner 3000万下载、发扬WLB、进军视频领域

    时光飞逝,岁月如梭,蓦然回首,已是年底. 感觉写 2020 年终总结还是在不久之前.转眼间,2021 已经接近尾声了.是时候来写写 2021 年的年终总结了. 内推 40 人 2019 年,内推了 2 ...

  7. Azure Data Lake(一) 在NET Core 控制台中操作 Data Lake Storage

    一,引言 Azure Data Lake Storage Gen2 是一组专用于大数据分析的功能,基于 Azure Blob Storage 构建的.Data Lake Storage Gen2 包含 ...

  8. Color Models (RGB, CMY, HSI)

    目录 概 定义 RGB CMY CMYK HSI 相互的转换 RGB <=> CMY CMY <=> CMYK CMY > CMYK CMYK > CMY RGB ...

  9. Intriguing Properties of Contrastive Losses

    目录 概 主要内容 广义对比损失 不同的先验 不同的权重比 Feature Suppression DigitOnImageNet dataset RandBit dataset 代码 [Chen T ...

  10. <学习opencv>图像和大型阵列类型

    OPenCV /*=========================================================================*/ // 图像和大型阵列类型 /* ...