Vue nextTick获取更新后的DOM的实现

目录
  • 生命周期 update
  • Vue.nextTick
  • Promise
  • 结语&参考资料

前两天在开发时遇到一个需求:打开对话框的时候自动聚焦其中的输入框。由于原生的 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-if 、watch 等。

在上文的例子中再加入 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 文档 - api

Vue 文档 - 实例

到此这篇关于Vue nextTick获取更新后的DOM的实现的文章就介绍到这了,更多相关Vue nextTick获取更新后的DOM内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • VUE异步更新DOM - 用$nextTick解决DOM视图的问题

    VUE异步更新DOM 首先,Vue 在更新 DOM 时是异步执行的! 所以只要侦听到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更.如果同一个 watcher 被多次触发,只会被推入到队列中一次.这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作是非常重要的.然后,在下一个的事件循环"tick"中,Vue 刷新队列并执行实际 (已去重的) 工作.Vue 在内部对异步队列尝试使用原生的 Promise.then.MutationObserver 和

  • 详解从Vue.js源码看异步更新DOM策略及nextTick

    写在前面 因为对Vue.js很感兴趣,而且平时工作的技术栈也是Vue.js,这几个月花了些时间研究学习了一下Vue.js源码,并做了总结与输出. 文章的原地址:https://github.com/answershuto/learnVue. 在学习过程中,为Vue加上了中文的注释https://github.com/answershuto/learnVue/tree/master/vue-src,希望可以对其他想学习Vue源码的小伙伴有所帮助. 可能会有理解存在偏差的地方,欢迎提issue指出,

  • 详解vue指令与$nextTick 操作DOM的不同之处

    异步更新队列 可能你还没有注意到,Vue 异步执行 DOM 更新.只要观察到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据改变.如果同一个 watcher 被多次触发,只会被推入到队列中一次.这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作上非常重要.然后,在下一个的事件循环"tick"中,Vue 刷新队列并执行实际 (已去重的) 工作.Vue 在内部尝试对异步队列使用原生的 Promise.then 和 MessageChannel,如果执行环境不

  • Vue nextTick获取更新后的DOM的实现

    目录 生命周期 update Vue.nextTick Promise 结语&参考资料 前两天在开发时遇到一个需求:打开对话框的时候自动聚焦其中的输入框.由于原生的 autofocus 属性不起作用,需要使用组件库提供的 focus 方法手动手动获取焦点.于是有如下代码: <el-button @click="openDialog">点击打开 Dialog</el-button> <el-dialog :visible.sync="dia

  • Vue nextTick延迟回调获取更新后DOM机制详解

    目录 简述 事件循环机制 vue数据驱动视图的处理(异步变化DOM) Vue.nextTick原理 Vue.nextTick的应用 created生命周期中操作DOM 修改数据,获取DOM值 简述 相信大家在写vue项目的时候,一定会发现一个神奇的api,Vue.nextTick.为什么说它神奇呢,那是因为在你做某些操作不生效时,将操作写在Vue.nextTick内,就神奇的生效了.那这是什么原因呢? 让我们一起来研究一下. vue 实现响应式并不是数据发生变化后 DOM 立即变化,而是按照一定

  • Vue动态获取数据后控件不可编辑问题

    目录 功能介绍 实现过程 1.做判断 2.在控件中使用editNotavailable 3.定义editNotavailable的初始状态 老规矩:先走波流程! 看实现效果,更好根据大家的问题相对应的解决自己的问题. 功能介绍 由动图可以看到,当我点击添加试题时,因为要添加些数据,跳转过去的界面必须是可以使用的.再当我点击编辑,携带过去的数据是不能更改的,只更改下方题干部分. 具体如何实现控件获得数据后不可更改呢?主要是用到判断,可以看到这里我只给input和select组件设置了不可用,但他们

  • 关于Vue.nextTick()的正确使用方法浅析

    本文主要给大家介绍了关于Vue.nextTick()的正确使用,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 什么是Vue.nextTick() 官方文档解释如下: 在下次 DOM 更新循环结束之后执行延迟回调.在修改数据之后立即使用这个方法,获取更新后的 DOM. 我理解的官方文档的这句话的侧重点在最后那半句获取更新后的DOM,获取更新后的DOM言外之意就是什么操作需要用到了更新后的DOM而不能使用之前的DOM或者使用更新前的DOM或出问题,所以就衍生出了这个获取更新后的D

  • 深入学习Vue nextTick的用法及原理

    Vue.nextTick是Vue官方给我们提供的一个API(方法),作用是在下次DOM更新循环结束之后执行延迟回调.在修改数据之后立即使用这个方法,获取更新后的DOM: 那么我们的理解是:当数据发生变化之后,DOM视图并不会立即更新,如果我们在发生变化之后立马去获取某个节点或者某个节点的值,很有可能结果就是undefined:因为Vue实现响应式并不是数据发生变化之后DOM立即变化,而是按一定的策略进行DOM的更新: 来看一个小demo: App.vue <template> <div

  • vue的状态更新方式(异步更新解决)

    目录 状态更新(异步更新解决) 解决方案 异步更新及nexttick 为什么需要异步更新 nextTick 原理 状态更新(异步更新解决) 在vue中状态更新是异步的,这一点和react中的setstate类似. 解决方案 非组件解决方案: <div id="example">{{message}}</div> var vm = new Vue({   el: '#example',   data: {     message: '123'   } }) vm.

  • 一文学会什么是vue.nextTick()

    目录 概念 原理 举例 应该什么时候使用vue.$nextTick()呢? 概念 在下次DOM更新循环结束之后执行延迟回调,在修改数据之后立即使用这个方法,获取更新后的DOM 简单理解: 为了去解决数据更新了但是视图不更新的问题,当数据更新了,在DOM渲染后,自动执行该函数 原理 Vue是异步执行dom更新的,一旦观察到数据变化,Vue就会开启一个队列,然后把在同一个事件循环 (event loop) 当中观察到数据变化的 watcher 推送进这个队列.如果这个watcher被触发多次,只会被

  • Vue NextTick介绍与使用原理

    目录 一.NextTick是什么 定义 理解 为什么要有nexttick 二.使用场景 三.实现原理 一.NextTick是什么 定义 在下次 DOM 更新循环结束之后执行延迟回调.在修改数据之后立即使用这个方法,获取更新后的 DOM. 理解 Vue在更新DOM时时异步执行的.当数据发生变化时,Vue将开启一个异步更新队列,视图需要等队列中所有数据变化完成之后,再统一进行更新. 举例: <body> <div id="app"> <div> <

  • Vue $nextTick 为什么能获取到最新Dom源码解析

    目录 正文 修改数据之后 update 方法 nextTick 方法里面怎么执行传进去更新方法 正文 <template> <p id='text'>{{text}}</p> <button @click='change'>click</button> </template> <script> export default { data() { return { text: 'hello world' } } method

  • Vue nextTick的原理解析

    使用过Vue的小伙伴们都知道,Vue里的nextTick可以获取到更新后的DOM, 今天我就来讲解下nextTick里面究竟做了什么? 开始讲解前,我们需要知道了解一个概念,那就是Event Loop Event Loop Event Loop翻译过来就是事件循环, 一个Event Loop会包括一个或多个task队列,持续线程会从队列中取出最早进入队列的任务进行执行,被取出的任务就叫做macroTask(宏任务), 每个macroTask都有一个任务源, 每个macroTask处理完之后就从队

随机推荐