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


Posted in Javascript onNovember 06, 2020

VUE异步更新DOM

首先,Vue 在更新 DOM 时是异步执行的!

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

例如,当你设置 vm.someData = ‘new value',该组件不会立即重新渲染。当刷新队列时,组件会在下一个事件循环“tick”中更新。多数情况我们不需要关心这个过程,但是如果你想基于更新后的 DOM 状态来做点什么,这就可能会有些棘手。虽然 Vue.js 通常鼓励开发人员使用“数据驱动”的方式思考,避免直接接触 DOM,但是有时我们必须要这么做。

解决办法

为了在数据变化之后等待 Vue 完成更新 DOM,可以在数据变化之后立即使用 Vue.nextTick(callback)。这样回调函数将在 DOM 更新完成后被调用。

例如:

<div id="example">{{message}}</div>

var vm = new Vue({
 el: '#example',
 data: {
  message: '123'
 }
})
vm.message = 'new message' // 更改数据
vm.$el.textContent === 'new message' // false
Vue.nextTick(function () {
 vm.$el.textContent === 'new message' // true
})

在组件内使用 vm.$nextTick() 实例方法特别方便,因为它不需要全局 Vue,并且回调函数中的 this 将自动绑定到当前的 Vue 实例上:

Vue.component('example', {
 template: '<span>{{ message }}</span>',
 data: function () {
  return {
   message: '未更新'
  }
 },
 methods: {
  updateMessage: function () {
   this.message = '已更新'
   console.log(this.$el.textContent) // => '未更新'
   this.$nextTick(function () {
    console.log(this.$el.textContent) // => '已更新'
   })
  }
 }
})

因为 $nextTick() 返回一个 Promise 对象,所以你可以使用新的 ES2017 async/await 语法完成相同的事情:

methods: {
 updateMessage: async function () {
  this.message = '已更新'
  console.log(this.$el.textContent) // => '未更新'
  await this.$nextTick()
  console.log(this.$el.textContent) // => '已更新'
 }
}

补充知识:Vue数据更新视图不更新,你必须知道的几种解决方案

知识拓展

在一个组件实例中,只有在data里初始化的数据才是响应的,Vue不能检测到对象属性的添加或删除,没有在data里声明的属性不是响应的。

Vue不允许在已经创建的实例上动态添加根级响应式属性,但是可以使用$set方法将相应属性添加到嵌套的对象上。

数组数据变动,使用某些方法操作数组,变动数据时,有些方法无法被vue监测

push(),pop(),shift(),unshift(),splice(),sort(),reverse()可被vue检测到

filter(), concat(), slice()。这些不会改变原始数组,但总是返回一个新数组。当使用非变异方法时,可以用新数组替换旧数组。

vue不能检测以下变动的数组:

1、当你利用索引直接设置一个项时,vm.items[indexOfItem] = newValue

2、当你修改数组的长度时,例如: vm.items.length = newLength

对象属性的添加或删除

由于 Vue 会在初始化实例时对属性执行 getter/setter 转化过程,所以属性必须在 data 对象上存在才能让 Vue 转换它,这样才能让它是响应的。

解决办法:

使用 Vue.set(object, key, value) 方法将响应属性添加到嵌套的对象上

Vue.set(vm.someObject, 'b', 2) 或者 this.$set(this.someObject,'b',2) (这也是全局 Vue.set 方法的别名)

异步更新队列

在最新的项目中遇到了这种情况,数据第一次获取到了,也渲染了,但是第二次之后数据只有在再一次渲染页面的时候更新,并不能实时更新。

网上查了资料才知道,Vue 异步执行 DOM 更新。只要观察到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据改变。如果同一个 watcher 被多次触发,只会被推入到队列中一次。

解决办法:

可在数据变化之后立即使用 Vue.nextTick(callback)。这样回调函数在 DOM 更新完成后就会调用。例如:

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

因为 $nextTick()返回一个 Promise 对象,所以可以使用新的 ES2016 async/await语法完成相同的事情:

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

Object.assign方法

object.assign方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象,并返回目标对象。

vm.object = Object.assign( { } , vm.object , {a:' 1 ', b:' 2 ' })

注:object必须是已经声明的对象

vue多层循环,动态改变数据后渲染的很慢或者不渲染

可在动态改变数据的方法,第一行加上

this.$forceUpdate();

以上这篇VUE异步更新DOM - 用$nextTick解决DOM视图的问题就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
jQuery asp.net 用json格式返回自定义对象
Apr 07 Javascript
javascript获取元素偏移量的方法有哪些
Jun 24 Javascript
JavaScript获取两个数组交集的方法
Jun 09 Javascript
Javascript实现的简单右键菜单类
Sep 23 Javascript
JavaScript:Date类型全面解析
May 19 Javascript
plupload+artdialog实现多平台上传文件
Jul 19 Javascript
AngularJS ngModel实现指令与输入直接的数据通信
Sep 21 Javascript
springMVC + easyui + $.ajaxFileUpload实现文件上传注意事项
Apr 23 Javascript
phantomjs导出html到pdf的方法总结
Oct 19 Javascript
vue自定义指令之面板拖拽的实现
Apr 14 Javascript
vue动态子组件的两种实现方式
Sep 01 Javascript
extjs4图表绘制之折线图实现方法分析
Mar 06 Javascript
nuxt.js服务端渲染中axios和proxy代理的配置操作
Nov 06 #Javascript
微信小程序开发数据缓存基础知识辨析及运用实例详解
Nov 06 #Javascript
nuxt 路由、过渡特效、中间件的实现代码
Nov 06 #Javascript
Nuxt的路由动画效果案例
Nov 06 #Javascript
微信小程序中target和currentTarget的区别小结
Nov 06 #Javascript
vue router-link 默认a标签去除下划线的实现
Nov 06 #Javascript
微信小程序调用后台service教程详解
Nov 06 #Javascript
You might like
PHP中替换键名的简易方法示例详解
2014/01/07 PHP
php实现的发送带附件邮件类实例
2014/09/22 PHP
php中替换字符串函数strtr()和str_repalce()的用法与区别
2016/11/25 PHP
PHP数据库处理封装类实例
2016/12/24 PHP
Symfony查询方法实例小结
2017/06/28 PHP
使用laravel的Eloquent模型如何获取数据库的指定列
2019/10/17 PHP
laravel框架select2多选插件初始化默认选中项操作示例
2020/02/18 PHP
很多人都是用下面的js刷新站IP和PV
2008/09/05 Javascript
jquery实现文本框数量加减功能的例子分享
2014/05/10 Javascript
浅谈jquery选择器 :first与:first-child的区别
2016/11/20 Javascript
html中通过JS获取JSON数据并加载的方法
2017/11/30 Javascript
基于vue2.0动态组件及render详解
2018/03/17 Javascript
Vue+Webpack完美整合富文本编辑器TinyMce的方法
2018/11/30 Javascript
详解超简单的react服务器渲染(ssr)入坑指南
2019/02/28 Javascript
小程序双头slider选择器的实现示例
2020/03/31 Javascript
详解微信小程序轨迹回放实现及遇到的坑
2021/02/02 Javascript
Python实现竖排打印传单手机号码易撕条
2015/03/16 Python
解决pyqt中ui编译成窗体.py中文乱码的问题
2016/12/23 Python
python中requests库session对象的妙用详解
2017/10/30 Python
Python实现点阵字体读取与转换的方法
2019/01/29 Python
对django 模型 unique together的示例讲解
2019/08/06 Python
自定义django admin model表单提交的例子
2019/08/23 Python
快速查找Python安装路径方法
2020/02/06 Python
Python hashlib模块的使用示例
2020/10/09 Python
CSS3旋转——彩色扇子兼容firefox浏览器
2013/06/04 HTML / CSS
Puccini乌克兰:购买行李箱、女士手袋网上商店
2020/08/06 全球购物
求职自荐信格式
2013/12/04 职场文书
《自然之道》教学反思
2014/02/11 职场文书
《李时珍夜宿古寺》教学反思
2014/04/09 职场文书
大学第二课堂活动总结
2014/07/08 职场文书
关于感恩的演讲稿200字
2014/08/26 职场文书
2014最新房贷收入证明范本
2014/09/12 职场文书
井冈山红色之旅感想
2014/10/07 职场文书
2015年教师党员公开承诺书
2015/01/22 职场文书
介绍信如何写
2015/01/31 职场文书
css3属性选择器 “~”(波浪号) “,”(逗号) “+”(加号)和 “>”(大于号)
2022/04/19 HTML / CSS