VUE|VUE this.$nextTick()的使用场景

【TAG - 1】:
官网解释:
将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新。
它跟全局方法 Vue.nextTick 一样,不同的是回调的 this 自动绑定到调用它的实例上。
个人理解:
用于直接操作dom元素的时候使用,由于直接操作dom元素时页面拿到的状态是修改之前的数据,这时需要使用到this.$nextTick,相当于setTimeout。
代码展示:

export default { data(){ return { a: '111' } } }


methods: { boxClick(){ this.a = '222'; // 由于dom元素还没有更新, 因此打印出来的还是未改变之前的值; console.log(that.$refs.box.innerText); //输出的是111 } }

methods: { boxClick(){ this.a= '222'; this.$nextTick(() => { // dom元素更新后执行, 因此此处能正确打印出更改之后的值; console.log(that.$refs.box.innerText); //输出的是222 }) } }




【TAG - 2】:
最近有在一个老项目的html页面中使用vue和echarts,点击按钮后需要重新渲染echart图标,但是echart却报错:Can't get dom width or height。可以很清楚知道是由于echarts获取不到宽度和高度,我试过使用this.$refs来过去元素的宽高,但还是失败了,所以,我觉得还是dom渲染问题,那么此时快速的解决办法就是使用this.$nextTick()方法。我从上面的使用结果可以知道,this.$nextTick()方法主要是用在随数据改变而改变的dom应用场景中,vue中数据和dom渲染由于是异步的,所以,要让dom结构随数据改变这样的操作都应该放进this.$nextTick()的回调函数中。created()中使用的方法时,dom还没有渲染,如果此时在该钩子函数中进行dom赋值数据(或者其它dom操作)时无异于徒劳,所以,此时this.$nextTick()就会被大量使用,而与created()对应的是mounted()的钩子函数则是在dom完全渲染后才开始渲染数据,所以在mounted()中操作dom基本不会存在渲染问题。
{{msg}} Message got outside $nextTick: {{msg1}} Message got inside $nextTick: {{msg2}} Message got outside $nextTick: {{msg3}} new Vue({ el: '.app', data: { msg: 'Hello Vue.', msg1: '', msg2: '', msg3: '' }, methods: { changeMsg() { this.msg = "Hello world." this.msg1 = this.$refs.msgDiv.innerHTML this.$nextTick(() => { this.msg2 = this.$refs.msgDiv.innerHTML }) this.msg3 = this.$refs.msgDiv.innerHTML } } })


点击前:
VUE|VUE this.$nextTick()的使用场景
文章图片

点击后:
VUE|VUE this.$nextTick()的使用场景
文章图片

从上图可知,vue中的msg1和msg3显示的数据还是赋值之前的,msg2显示的数据则是赋值之后的。其根本原因是vue中的dom渲染是异步的。

【TAG - 3】 :
this.$nextTick 将回调延迟到下次DOM更新循环之后执行。在修改数据之后立即使用它,然后等待DOM更新。
this.$nextTick 跟全局方法 vue.nextTick 一样,不同的是,回调的 this 自动绑定到调用它的实例上。
总的来说,假设我们更改了某个 dom 元素内部的文本,而这时候我们想直接打印这个更改之后的文本是需要 dom 更新之后才会实现的,就像我们把将要打印输出的代码放在 setTimeout(fn, 0) 中
具体demo如下


this.$nextTick这个方法作用是当数据被修改后使用这个方法会回调获取更新后的dom再渲染出来
methods:{ testClick() { this.content = '改变了的值' this.$nextTick(() => { // dom元素更新后执行,因此这里能正确打印更改之后的值 console.log(that.$refs.tar.innerText) // 改变了的值 }) } }

$nextTick
Vue.nectTick() 是在下次DOM更新循环结束之后执行延迟回调,在修改数据之后使用$nextTick,则可以在回调中获取更新后的DOM(dom的改变是发生在nextTick()之后),这个方法作用是当数据被修改后使用这个方法,会回调获取更新后的dom再render出来
Vue.nextTick()作用:在下次dom更新循环结束之后,执行延迟回调。在修改数据之后立即使用这个方法,获得更新后的dom
在以下两个情况下需要用到Vue.nextTick()
1、Vue声明周期的created() 钩子函数进行的DOM操作一定要放在Vue.nextTick() 的回调函数中,因为created() 执行的时候DOM实际上并未进行任何渲染,此时进行DOM操作无异于徒劳,所以此处一定要将DOM操作的js代码放进Vue.nextTick()的回调函数中。
与之对应的就是mounted 钩子函数,因为该函数执行时所有的DOM挂载和渲染都已完成,此时再钩子函数中进行任何DOM操作都不会有问题。
2、在数据变化后要执行的某个操作,而这个操作需要使用随数据改变而改变的DOM结构的时候,这个操作应该放进Vue.nextTick() 的回调函数中
简而言之,如果你在数据改变之后的操作跟改变之后的DOM有关,那么就应该使用Vue.nextTick()

Vue中this.$nextTick的作用及用法 Vue实现响应式后DOM的变化
data对象中数据改变是如何追踪的?
vue将遍历data对象中所有的属性,并通过 Object.defineProperty 把这些属性全部转为 getter/setter;但是我们是没有办法看到 getter/setter的,但是在内部它们让 Vue 能够追踪依赖,在属性被访问和修改时通知变更。
每个组件都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据属性记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。
Vue是无法检测到data对象属性的添加和删除
原因:Vue在对初始化组件时会对对象属性执行getter/setter转化,所以属性必须在data对象上存在才能让Vue将它转化为初始化。
var vm = new Vue({ data:{ a:1 } })

// vm.a 是响应式的
vm.b = 2
// vm.b 是非响应式的
如何动态添加根级别的响应式属性【就是对data添加属性】
this.$set(this.someObject,'b',2)

异步更新队列
Vue 在更新 DOM 时是异步执行的。只要侦听到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。
如果同一个 watcher 被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作是非常重要的。
然后,在下一个的事件循环“tick”中,Vue 刷新队列并执行实际 (已去重的) 工作。
Vue 在内部对异步队列尝试使用原生的 Promise.then、MutationObserver 和 setImmediate,如果执行环境不支持,则会采用 setTimeout(fn, 0) 代替。
例如,当你设置 vm.someData = 'https://www.it610.com/article/new value',该组件不会立即重新渲染。
【VUE|VUE this.$nextTick()的使用场景】当刷新队列时,组件会在下一个事件循环“tick”中更新。
多数情况我们不需要关心这个过程,但是如果你想基于更新后的 DOM 状态来做点什么,这就可能会有些棘手。虽然 Vue.js 通常鼓励开发人员使用“数据驱动”的方式思考,避免直接接触 DOM,但是有时我们必须要这么做。为了在数据变化之后等待 Vue 完成更新 DOM,可以在数据变化之后立即使用 Vue.nextTick(callback)。这样回调函数将在 DOM 更新完成后被调用。例如:
{{message}} 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: '{{ message }}', 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 实现响应式并不是数据发生变化之后 DOM 立即变化,而是按一定的策略进行 DOM 的更新。
$nextTick 是在下次 DOM 更新循环结束之后执行延迟回调,在修改数据之后使用 $nextTick,则可以在回调中获取更新后的 DOM
实例化理解Vue响应化

Price :¥{{ price }}
Total:¥{{ price * quantity }}
Taxes: ¥{{ totalPriceWithTax }}


var app = new Vue({
el: ‘#app’,
data() {
return {
price: 5.0,
quantity: 2
};
},
computed: {
totalPriceWithTax() {
return this.price * this.quantity * 1.03;
}
},
methods: {
changePrice() {
this.price = 10;
}
}
})
VUE|VUE this.$nextTick()的使用场景
文章图片

上例中当price 发生变化的时候,Vue就知道自己需要做三件事情:
  • 更新页面上price的值
  • 计算表达式 price*quantity 的值,更新页面
  • 调用totalPriceWithTax 函数,更新页面
数据发生变化后,会重新对页面渲染,这就是Vue响应式,那么这一切是怎么做到的呢?
想完成这个过程,我们需要:
  • 侦测数据的变化
  • 收集视图依赖了哪些数据
  • 数据变化时,自动“通知”需要更新的视图部分,并进行更新
对应专业俗语分别是:
  • 数据劫持 / 数据代理
  • 依赖收集
  • 发布订阅模式
总结
再来回顾下整个过程:
VUE|VUE this.$nextTick()的使用场景
文章图片

在new Vue()后, Vue 会调用_init函数进行初始化,也就是init 过程,在 这个过程Data通过Observer转换成了getter/setter的形式,来对数据追踪变化,当被设置的对象被读取的时候会执行getter函数,而在当被赋值的时候会执行setter函数。
当外界通过Watcher读取数据时,会触发getter从而将Watcher添加到依赖中。
在修改对象的值的时候,会触发对应的setter,setter通知之前依赖收集得到的 Dep 中的每一个 Watcher,告诉它们自己的值改变了,需要重新渲染视图。这时候这些 Watcher就会开始调用update来更新视图。
以上就是本次介绍的全部相关知识点内容
转载:https://www.jb51.net/article/179422.htm

    推荐阅读