nextTick那些事儿

72 篇文章 4 订阅

nextTick在项目中也是经常用到,蛮重要的一个api,在面试中可能也会问到,今天也是闲着没事儿干,就简单说一说nextTick那些事儿

Vue中有个异步更新策略,意思就是如果数据变化,Vue不会立刻更新DOM,而是开启一个队列,把组件更新函数保存在队列中,在同一事件循环中发生的所有数据变更会异步的批量更新。这一策略导致我们对数据的修改不会立刻体现在DOM上,此时如果想要获取更新后的DOM,就需要使用 nextTick。

我们要知道的是DOM的加载、渲染是个异步过程 ,这个一定要知道 

1. nextTick是什么 

nextTick是等待下次DOM更新刷新的工具方法

一般写法有下面两种,以在created中使用nextTick为例 

// 第一种写法
created() {
  this.$nextTick(() => {
    // dom更新完成后,要做些什么事儿
  })
},
// 第二种写法
async created() {
  await this.$nextTick()
  // dom更新完成后,要做些什么事儿
},

nextTick前面为什么可以用 await ? 这是因为nextTick返回就是个Promise 

nextTick签名如下: 

`function nextTick(callback?: () => void): Promise<void>`

就是当dom元素更新完成之后回去回调callback,所以我们只需要在传入的回调函数中访问最新的DOM即可,或者我们可以 await nextTick() 方法返回的Promise之后做这件事

2. 使用场景 

 使用nextTick场景一般有两种:

① 想在created中获取DOM(面试也会经常问) 

② 响应数据变化后、或者通过v-if控制的DOM刚挂载,我们要获取更新后的状态 (实际项目中经常用到)

第一种: 在created中获取DOM

大家都知道created中只是组件创建完成、不可能拿到dom元素的,在Mounted钩子函数中才可以拿到,但是我们就想在created中拿到呢(这种就是故意找茬,专为面试而用)?

其实方法也不只是nextTick,咱们加个setTimeout也是可以的 ,这是因为,created -> mounted的过程是同步的,但如果created中有异步代码,那就会将其放在队列中,先把同步代码走完,整体的一个顺序大概就是这样子的:

created同步代码 - > mounted同步代码(这时候dom已经挂载完成) ->  created异步代码 -> mounted异步代码

所以在created中获取dom,下面两种方式都是可以的 

<template>
  <div>
    <div id="myDiv">测试div</div>
  </div>
</template>
<script>
const $ = name => document.querySelector(name)
export default {
  created() {
    // 方式一
    setTimeout(() => {
      console.log($('#myDiv'), 'setTimeout----->>>')
    })
    // 方式二
    this.$nextTick(() => {
      console.log($('#myDiv'), 'nextTick----->>>')
    })
  }
};
</script>

大家看下控制它打印 

 

都可以顺利的拿到,但是有一点儿还要注意:nextTick 比 setTimeout执行时机要早。 

第二种:响应数据变化后,要获取到最新的dom状态 

这里用一个例子来说明:

我有一个数组list, list中默认有一条数据,我在template上v-for循环展示(在myDiv下面),然后我会有个按钮点击, 点击的时候我要拿到myDiv的孩子的个数

<template>
  <div>
    <div id="myDiv">
      <div v-for="item in list" :key="item.id">{{ item.name }}--</div>
    </div>
    <button @click="addList">添加</button>
  </div>
</template>
<script>
const $ = name => document.querySelector(name)
export default {
  data() {
    return {
      list: [{ name: 'wft', id: 0 }]
    }
  },
  methods: {
    addList() {
      this.list.push({
        id: this.list.length,
        name: `wft${this.list.length}`
      })
      console.log($('#myDiv').childNodes.length, '----->>>')
    }
  }
};
</script>

就上面的代码,当我点击第一次的时候, 是不是应该打印出2,这也是我们想要的结果。但实时并非如此,页面上确实能看到加了一条,但打印出1,也就是我们刚加进去的那条数据,并没有打印出来,这就是Vue的异步更新策略,我们想获取到DOM异步更新之后的状态,就需要使用nextTick了,只需要将上面的console.log,写在nextTick回调中即可

this.$nextTick(() => {
  console.log($('#myDiv').childNodes.length, '----->>>')
})

还有一种情况是,当我们用v-if控制DOM的显示的时候,我们不能马上对其操作,这时候可能也得需要nextTick,还有弹窗的打开、DOM的挂载,完事儿对其进行初始化操作等,都要注意一下

反正Vue中涉及到DOM的挂载的时候,脑袋瓜子里一定要想到Vue的异步更新策略、DOM的异步加载,要不然BUG就找到你了

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

会说法语的猪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值