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

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 更新完成后就会调用。例如:

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

Object.assign方法

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

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

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

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

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

this.$forceUpdate();

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

(0)

相关推荐

  • vue中$nextTick的用法讲解

    vue是非常流行的框架,他结合了angular和react的优点,从而形成了一个轻量级的易上手的具有双向数据绑定特性的mvvm框架.本人比较喜欢用之.在我们用vue时,我们经常用到一个方法是this.$nextTick,相信你也用过.我常用的场景是在进行获取数据后,需要对新视图进行下一步操作或者其他操作时,发现获取不到dom.因为赋值操作只完成了数据模型的改变并没有完成视图更新.在这个时候我们需要用到本章介绍的函数. 虽然 Vue.js 通常鼓励开发人员沿着"数据驱动"的方式思考,避免

  • 解决vue项目获取dom元素宽高总是不准确问题

    dom元素内部内容是动态的,重置数据后直接获取宽高总是不准确: this.$refs.editor[0].offsetHeight; 原因:重置数据后获取dom元素宽高时,dom元素还未渲染完毕: 解决方法:利用Vue.nectTick(callback) this.$nextTick(() => { this.$refs.editor[0].offsetHeight; }) Vue.nectTick() 是在下次DOM更新循环结束之后执行延迟回调 补充知识:vue 获取 指定元素的高度宽度等(

  • Vue 解决通过this.$refs来获取DOM或者组件报错问题

    1.关于this.$refs的使用场景 如果ref属性加在普通元素上,那么this.$refs.name则指向该DOM元素 <p ref="p">hello</p> <!-- this.$refs.p 指向该DOM元素 --> 如果ref属性加在组件上,那么this.$refs.name指向该组件实例 <child-component ref="child"></child-component> <!

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

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

  • Vue异步更新机制及$nextTick原理的深入讲解

    目录 前言 Vue的异步更新 DOM更新是异步的 DOM更新还是批量的 事件循环 执行过程 源码深入 异步更新队列 nextTick $nextTick 总结 一般更新DOM是同步的 既然更新DOM是个同步的过程,那为什么Vue却需要借用$nextTick来处理呢? 为什么优先使用微任务? 总结 前言 相信很多人会好奇Vue内部的更新机制,或者平时工作中遇到的一些奇怪的问题需要使用$nextTick来解决,今天我们就来聊一聊Vue中的异步更新机制以及$nextTick原理 Vue的异步更新 可能

  • vue异步更新dom的实现浅析

    目录 Vue异步更新DOM的原理 1 什么时候能获取到真正的DOM元素? 2 为什么Vue需要通过nextTick方法才能获取最新的DOM? 3 为什么this.$nextTick 能够获取更新后的DOM? 总结:vue异步更新的原理 Data对象:vue中的data方法中返回的对象: Dep对象:每一个Data属性都会创建一个Dep,用来搜集所有使用到这个Data的Watcher对象: Watcher对象:主要用于渲染DOM Vue异步更新DOM的原理 Vue中的数据更新是异步的,意味着我们在

  • 详解Vue的异步更新实现原理

    最近面试总是会被问到这么一个问题:在使用vue的时候,将for循环中声明的变量i从1增加到100,然后将i展示到页面上,页面上的i是从1跳到100,还是会怎样?答案当然是只会显示100,并不会有跳转的过程. 怎么可以让页面上有从1到100显示的过程呢,就是用setTimeout或者Promise.then等方法去模拟. 讲道理,如果不在vue里,单独运行这段程序的话,输出一定是从1到100,但是为什么在vue中就不一样了呢? for(let i=1; i<=100; i++){ console.

  • vue中的任务队列和异步更新策略(任务队列,微任务,宏任务)

    目录 事件循环 任务队列 如何理解微任务和宏任务? 深究Vue异步更新策略原理 事件循环 JavaScript 语言的一大特点就是单线程,也就是说,同一个时间只能做一件事. 为了协调事件.用户交互.脚本.UI 渲染和网络处理等行为,防止主线程的不阻塞,Event Loop 的方案应用而生. Event Loop 包含两类: 一类是基于 Browsing Context 一种是基于 Worker 二者的运行是独立的,也就是说,每一个 JavaScript 运行的"线程环境"都有一个独立的

  • vue源码之批量异步更新策略的深入解析

    vue异步更新源码中会有涉及事件循环.宏任务.微任务的概念,所以先了解一下这几个概念. 一.事件循环.宏任务.微任务 1.事件循环Event Loop:浏览器为了协调事件处理.脚本执行.网络请求和渲染等任务而定制的工作机制. 2.宏任务Task: 代表一个个离散的.独立的工作单位.浏览器完成一个宏任务,在下一个宏任务开始执行之前,会对页面重新渲染.主要包括创建文档对象.解析HTML.执行主线JS代码以及各种事件如页面加载.输入.网络事件和定时器等. 3.微任务:微任务是更小的任务,是在当前宏任务

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

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

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

  • Vue批量更新dom的实现步骤

    目录 场景介绍 深入响应式 触发getter 寻找Dep.target getter setter 总结 场景介绍 在一个SFC(single file component,单文件组件)中,我们经常会写这样的逻辑: <template> <div> <span>{{ a }}</span> <span>{{ b }}</span> </div> </template> <script type="

随机推荐