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 相关文章推荐
推荐:极酷右键菜单
Nov 29 Javascript
解决FLASH需要点击激活的代码
Dec 20 Javascript
javascript:文字不间断向左移动的实例代码
Aug 08 Javascript
jquery获得同源iframe内body下标签的值的方法
Sep 25 Javascript
JavaScript实现简单的二级导航菜单实例
Apr 15 Javascript
jQuery取得iframe中元素的常用方法详解
Jan 14 Javascript
在JavaScript中调用Java类和接口的方法
Sep 07 Javascript
浅谈javascript:两种注释,声明变量,定义函数
Oct 05 Javascript
详解vue与后端数据交互(ajax):vue-resource
Mar 16 Javascript
Three.js如何实现雾化效果示例代码
Sep 27 Javascript
vue2.0路由切换后页面滚动位置不变BUG的解决方法
Mar 14 Javascript
vue点击按钮实现简单页面的切换
Sep 08 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
一个分页的论坛
2006/10/09 PHP
PHP生成唯一的促销/优惠/折扣码(附源码)
2012/12/28 PHP
js和php邮箱地址验证的实现方法
2014/01/09 PHP
php查找指定目录下指定大小文件的方法
2014/11/28 PHP
php简单获取文件扩展名的方法
2015/03/24 PHP
[原创]php正则删除img标签的方法示例
2017/05/27 PHP
Laravel 5.4向IoC容器中添加自定义类的方法示例
2017/08/15 PHP
php使用curl伪造浏览器访问操作示例
2019/09/30 PHP
JavaScript对象创建及继承原理实例解剖
2013/02/28 Javascript
js 删除数组的几种方法小结
2014/02/21 Javascript
JS+CSS实现TreeMenu二级树形菜单完整实例
2015/09/18 Javascript
JSONP跨域请求实例详解
2016/07/04 Javascript
利用vue组件自定义v-model实现一个Tab组件方法示例
2017/12/06 Javascript
使用 vue-i18n 切换中英文效果
2018/05/23 Javascript
15分钟深入了解JS继承分类、原理与用法
2019/01/19 Javascript
ES6 Promise对象概念及用法实例详解
2019/10/15 Javascript
vue+render+jsx实现可编辑动态多级表头table的实例代码
2020/04/01 Javascript
es6数组的flat(),flatMap()函数用法实例分析
2020/04/18 Javascript
跟老齐学Python之list和str比较
2014/09/20 Python
python实现批量解析邮件并下载附件
2018/06/19 Python
Python爬虫实现抓取京东店铺信息及下载图片功能示例
2018/08/07 Python
利用Python对文件夹下图片数据进行批量改名的代码实例
2019/02/21 Python
Python Django框架单元测试之文件上传测试示例
2019/05/17 Python
Pytorch之finetune使用详解
2020/01/18 Python
Python while循环使用else语句代码实例
2020/02/07 Python
英国第一的市场和亚马逊替代品:OnBuy
2019/03/16 全球购物
德国高尔夫商店:Golfshop.de
2019/06/22 全球购物
Linux管理员面试题 Linux admin interview questions
2016/07/08 面试题
如何理解transaction事务的概念
2015/05/27 面试题
公司的门卫岗位职责
2014/09/09 职场文书
商业用房租赁协议书
2014/10/13 职场文书
技术股东合作协议书
2014/12/02 职场文书
2014年中班下学期工作总结
2014/12/11 职场文书
2014年党总支工作总结
2014/12/18 职场文书
为什么RedisCluster设计成16384个槽
2021/09/25 Redis
Java实现房屋出租系统详解
2021/10/05 Java/Android