likes
comments
collection
share

用“800亿”给学前端的小少爷讲清楚Vue.nextTick

作者站长头像
站长
· 阅读数 20

hello,大家好,我是小秃,相信学习过Vue的同学一定接触过nextTick这个API,并且各大Vue的相关课程也基本上会着重讲解这个知识点,可他具体是做什么用的呢?为什么要有他的存在。今天这一篇文章将会一一解答,话不多说,发车! 温馨提示:本篇文章主要针对小白哦~ 大佬们加油探索更深的东西吧,但是也欢迎指正哦~

什么是NextTick

简单来说,nextTick是Vue提供的一个全局API,他的出现主要是为了解决,某些对异步渲染完成之后的结构进行处理的业务逻辑。是不是听不懂呢?😜说人话就是,某些时候你希望等页面渲染完成后(DOM结构形成)再去操作形成的DOM,虽然Vue本身不提倡开发者直接操作DOM,但是在一些特殊情况下你不得不这么做,这个时候nextTick就发挥出了它的作用。

是不是还不理解他的使用场景呢?

举个🌰,你亲爱的母上大人在你们家别墅的后花园里撒了些种子,打算种些白菜出来,但是你妈妈着急出差去谈你们家800亿的大生意要走大半年,临走时交代你说,等白菜长出来数数有几棵,于是就走了,其实平时你是不用管种菜的事的,这时候你必须要管了,而且你必须要等菜长出来才知道有几颗,才能数,那么对于你妈妈来说,她希望菜一长出来你就去数,但是她又不能等菜长出来再来交代你(别问为啥不能,问就是800亿生意没时间。。。),所以提前交代你。 那么如何保证你能按照要求及时数菜,这就是nextTick的作用,他保证只要菜一长出来,就会让你去数。

回到Vue中的使用场景

你现在从服务器接收一个数组,数组将会以无序列表(ul)的形式渲染到页面上,渲染完成后你需要针对渲染后的列表的某一项进行一些操作,很简单的我们可以在书写html时为每个li添加ref然后在方法中获取,循环遍历进行业务实现。

<template>
  <div id="app">
    <ul id="container">
      <li ref="item" v-for="p of list" :key="p.id">
        {{ `name:${p.name}gender:${p.gender}age:${p.age}` }}
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      list: [],
    };
  },
  watch: {
    list() {
      let items = this.$refs.item;
      for (let i = 0; i < items.length; i++) {
        if (i === 1) {
          items[i].className = "active";
        }
      }
    },
  },
  mounted() {
    setTimeout(() => {
      this.list = [
        { id: 1, name: "章三", gender: 1, age: 23 },
        { id: 2, name: "里斯", gender: 1, age: 24 },
        { id: 3, name: "王麻子", gender: 1, age: 45 },
      ];
    }, 3000);
  },
  components: {},
};
</script>

<style lang="css" scoped>
ul {
  list-style: none;
}
.active {
  color: orange;
}
</style>

以上代码我们使用定时器模拟获取数据,当watch检测到数据,执行回调,回调中主要是为列表第2项添加一个样式类名active,看似是不是非常完美? 但是理想很丰满,现实很骨感。如果你执行以上代码会发现

用“800亿”给学前端的小少爷讲清楚Vue.nextTick

为什么报错?

观察报错不难发现,他说我们获取的DOM集合items没有length属性,其实就是说我们压根就没有获取到DOM集合,那为什么呢?因为此时DOM结构压根就没有渲染出来,自然我们取不到。

为什么取不到?

这就要说到vue渲染DOM的策略了,按照我们的惯性思维,它应该是只要数据修改,页面就立马更新,也就是同步渲染。确实这样做没有问题,但是如果数据的修改频繁的话,那么频繁渲染必然会带来一些性能的损耗,所以vue并没有这么做,而是选择集中处理页面的渲染,也就是说,vue采取异步渲染。它选择在每次事件循环的最后进行页面的更新(针对事件循环我们这里不做过多赘述,忘记或者不太熟悉的同学可以找找这方面的介绍),鉴于事件循环的存在,很明显在执行watch中的回调的时候,页面并没有渲染出来,自然也就没办法获取到DOM集合啦。 那么此时就可以请出我们的nextTick来帮助我们了,其实主要是修改watch内的代码

watch: {
    list() {
    //这里的$nextTick与Vue.nextTick没有区别,只不过$nextTick是暴露在组件实例身上的而已
      this.$nextTick(() => {
        let items = this.$refs.item;
        for (let i = 0; i < items.length; i++) {
          if (i === 1) {
            items[i].className = "active";
          }
        }
      });
    },
  },

此时,我们将之前的代码包装成nextTick的回调,那么它就可以帮我们做到等页面更新后执行我们的代码,确保获取到DOM集合。

联系🌰与实际应用

通过我们800亿小生意的例子与实际应用场景,我们讲解了nextTick的用法与使用场景以及它的作用。为了更好的理解,我们再将它们串一遍。 上面的例子,我们提到了几个关键点

  1. 等白菜长出来数数有几棵
  2. 必须要等菜长出来才知道有几颗,才能数
  3. 母亲希望菜一长出来你就去数,但是她又不能等菜长出来再来交代你

我们前后联系一下其实应该可以发现,关键点1就是我们实际应用场景中的等列表渲染后再操作,而且我们(关键点2必须等待列表渲染之后才能获取items,所以我们希望(关键点3列表一渲染,就立马去执行我们要做的操作,但我们又不能等待他渲染出来之后再去处理操作

注意,这里当我们说到不能等到数据渲染出来之后再去处理时,一些同学可能立马想到,完全可以等到渲染出来呀,我开一个定时器,延迟执行我的操作不就好啦,这样确实可行,但是延迟的时间上很不好把握,时间短了不起作用,时间长了又很影响体验。

总结

Vue.nextTick其实是Vue内部为满足一些特殊业务场景而暴露出的一个API,它可以保证我们的某些操作针对的一定是更新后的页面,熟练的使用在某些场景下可以简化我们的业务实现逻辑哦。

感觉还可以的话,留下小心心慰藉一下小秃的“小秃头”吧~