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 相关文章推荐
Tinymce+jQuery.Validation使用产生的BUG
Mar 29 Javascript
jQuery autocomplate 自扩展插件、自动完成示例代码
Mar 28 Javascript
用jquery实现输入框获取焦点消失文字
Apr 27 Javascript
JavaScript加强之自定义callback示例
Sep 21 Javascript
jQuery控制Div拖拽效果完整实例分析
Apr 15 Javascript
javascript实现动态导入js与css等静态资源文件的方法
Jul 25 Javascript
8 行 Node.js 代码实现代理服务器
Dec 05 Javascript
vue的基本用法与常见指令
Aug 15 Javascript
vue 简单自动补全的输入框的示例
Mar 12 Javascript
Element-ui之ElScrollBar组件滚动条的使用方法
Sep 14 Javascript
Vue中CSS动画原理的实现
Feb 13 Javascript
详解Vue+elementUI build打包部署后字体图标丢失问题
Jul 13 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连mysql和oracle数据库性能比较
2006/10/09 PHP
PHP+MYSQL的文章管理系统(二)
2006/10/09 PHP
第十五节--Zend引擎的发展
2006/11/16 PHP
PHP中UNIX时间戳和日期间的转换与计算实例
2014/11/19 PHP
10个超级有用的PHP代码片段果断收藏
2015/09/23 PHP
PHP实现限制IP访问的方法
2017/04/20 PHP
laravel 时间格式转时间戳的例子
2019/10/11 PHP
利用onresize使得div可以随着屏幕大小而自适应的代码
2010/01/15 Javascript
javascript学习笔记(十四) window对象使用介绍
2012/06/20 Javascript
Javascript的数组与字典用法与遍历对象的属性技巧
2012/11/07 Javascript
javascript 构造函数方式定义对象
2015/01/02 Javascript
js获取checkbox值的方法
2015/01/28 Javascript
jQuery检测滚动条是否到达底部
2015/12/15 Javascript
ES6新特性之类(Class)和继承(Extends)相关概念与用法分析
2017/05/24 Javascript
Angular4 中常用的指令入门总结
2017/06/12 Javascript
详解Angular Reactive Form 表单验证
2017/07/06 Javascript
JavaScript DOM元素常见操作详解【添加、删除、修改等】
2018/05/09 Javascript
Javascript Web Worker使用过程解析
2020/03/16 Javascript
vue+elementUI(el-upload)图片压缩,默认同比例压缩操作
2020/08/10 Javascript
python基础教程之python消息摘要算法使用示例
2014/02/10 Python
python实现的用于搜索文件并进行内容替换的类实例
2015/06/28 Python
Python中的迭代器与生成器高级用法解析
2016/06/28 Python
浅谈python字符串方法的简单使用
2016/07/18 Python
Python整数与Numpy数据溢出问题解决
2019/09/11 Python
Python实现非正太分布的异常值检测方式
2019/12/09 Python
浅谈keras保存模型中的save()和save_weights()区别
2020/05/21 Python
python属于哪种语言
2020/08/16 Python
HTML5页面中尝试调起APP功能
2017/09/12 HTML / CSS
html+js 实现markdown编辑器效果
2019/10/23 HTML / CSS
财政专业求职信范文
2014/02/19 职场文书
个性车贴标语
2014/06/24 职场文书
2014年底个人工作总结
2015/03/10 职场文书
医院志愿者活动总结
2015/05/06 职场文书
安全教育片观后感
2015/06/17 职场文书
邓小平文选读书笔记
2015/06/29 职场文书
总结会主持词
2015/07/02 职场文书