Vue中的$nextTick()

上篇文章大概说了$nextTick()的定义

下面给大家举例说明:

Html结构

<div id="app"> {{ message }} </div>
const vm = new Vue({
  el: '#app',
  data: {
    message: '原始值'
  }
})

this.message = '修改后的值1'
this.message = '修改后的值2'
this.message = '修改后的值3'

这时候想获取页面最新的DOM节点,却发现获取到的是旧值
console.log(vm.$el.textContent) // 原始值
这是因为message数据在发现变化的时候,vue并不会立刻去更新Dom,
而是将修改数据的操作放在了一个异步操作队列中

如果我们一直修改相同数据,异步操作队列还会进行去重

等待同一事件循环中的所有数据变化完成之后,会将队列中的事件拿来进行处理,进行DOM的更新

1.为什么要有nexttick


<div>{{num}}</div>

for(let i=0; i<100000; i++){
    num = i
}

如果没有 nextTick 更新机制,那么 num每次更新值都会触发视图更新(上面这段代码也就是会更新10万次视图),
有了nextTick机制,只需要更新一次,所以nextTick本质是一种优化策略

2.使用场景

下面了解下nextTick的主要应用的场景及原因。

 - 在Vue生命周期的created()钩子函数进行的DOM操作一定要放在Vue.nextTick()的回调函数中

	在created()钩子函数执行的时候DOM 其实并未进行任何渲染,而此时进行DOM操作无异于徒劳,
所以此处一定要将DOM操作的js代码放进
	Vue.nextTick()的回调函数中。与之对应的就是mounted()钩子函数,因为该钩子函数执行时所有的
DOM挂载和渲染都已完成,此时在该钩子函数中进行任何DOM操作都不会有问题 。

 - 在数据变化后要执行的某个操作,而这个操作需要使用随数据改变而改变的DOM结构的时候,
 这个操作都应该放进Vue.nextTick()的回调函数中。



如果想要在修改数据后立刻得到更新后的DOM结构,可以使用Vue.nextTick()

第一个参数为:回调函数(可以获取最近的DOM结构)

第二个参数为:执行函数上下文

**如果没有提供回调函数,那么将返回promise对象。**
// 修改数据
vm.message = '修改后的值'
// DOM 还没有更新
console.log(vm.$el.textContent) // 原始的值
Vue.nextTick(function () {
  // DOM 更新了
  console.log(vm.$el.textContent) // 修改后的值
})

组件内使用 vm. $nextTick()实例方法只需要通过this. $nextTick(),并且回调函数中的 this 将自动绑定到当前的 Vue 实例上

this.message = '修改后的值'
console.log(this.$el.textContent) // => '原始的值'
this.$nextTick(function () {
    console.log(this.$el.textContent) // => '修改后的值'
})

$nextTick()会返回一个 Promise 对象,可以是用async/await完成相同作用的事情

this.message = '修改后的值'
console.log(this.$el.textContent) // => '原始的值'
await this.$nextTick()
console.log(this.$el.textContent) // => '修改后的值'

3.实现原理

首先,先了解nextTick中定义的三个重要变量。

  • callbacks

     用来存储所有需要执行的回调函数
    
  • pending

     用来标志是否正在执行回调函数
    
  • timerFunc

     用来触发执行回调函数
    

接下来,了解nextTickHandler()函数。

function nextTickHandler () {
    pending = false
    const copies = callbacks.slice(0)
    callbacks.length = 0
    for (let i = 0; i < copies.length; i++) {
      copies[i]()
    }
  }

这个函数用来执行callbacks里存储的所有回调函数。

接下来是将触发方式赋值给timerFunc。

 - 先判断是否原生支持promise,如果支持,则利用promise来触发执行回调函数;
 - 否则,如果支持MutationObserver,则实例化一个观察者对象,观察文本节点发生变化时,
 - 触发执行所有回调函数。
- 如果都不支持,则利用setTimeout设置延时为0。


	最后是queueNextTick函数。因为nextTick是一个即时函数,
	所以queueNextTick函数是返回的函数,接受用户传入的参数,用来往callbacks里存入回调函数。

timeFunc(),该函数起到延迟执行的作用。

从上面的介绍,可以得知timeFunc()一共有三种实现方式。

  • Promise
  • MutationObserver
  • setTimeout

其中Promise和setTimeout很好理解,是一个异步任务,会在同步任务以及更新DOM的异步任务之后回调具体函数。

MutationObserver是HTML5中的新API,是个用来监视DOM变动的接口。他能监听一个DOM对象上发生的子节点删除、属性修改、文本内容修改等等。

调用过程很简单 你需要先给他绑回调:

var mo = new MutationObserver(callback)
通过给MutationObserver的构造函数传入一个回调,能得到一个MutationObserver实例,
这个回调就会在MutationObserver实例监听到变动时触发。

这个时候你只是给MutationObserver实例绑定好了回调,他具体监听哪个DOM、监听节点删除还是监听属性修改,还没有设置。而调用他的observer方法就可以完成这一步:

var domTarget = 你想要监听的dom节点
mo.observe(domTarget, {
      characterData: true //说明监听文本内容的修改。
})

其实使用 MutationObserver的原因就是 nextTick想要一个异步API,用来在当前的同步代码执行完毕后,执行我想执行的异步回调,包括Promise和 setTimeout都是基于这个原因

小结:

  • 把回调函数放入callbacks等待执行
  • 将执行函数放到微任务或者宏任务中
  • 事件循环到了微任务或者宏任务,执行函数依次执行callbacks中的回调
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值