用“800亿”给学前端的小少爷讲清楚Vue.nextTick
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
,看似是不是非常完美?
但是理想很丰满,现实很骨感。如果你执行以上代码会发现
为什么报错?
观察报错不难发现,他说我们获取的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)必须等待列表渲染之后才能获取items
,所以我们希望(关键点3)列表一渲染,就立马去执行我们要做的操作,但我们又不能等待他渲染出来之后再去处理操作
。
注意,这里当我们说到不能等到数据渲染出来之后再去处理时,一些同学可能立马想到,完全可以等到渲染出来呀,我开一个定时器,延迟执行我的操作不就好啦,这样确实可行,但是延迟的时间上很不好把握,时间短了不起作用,时间长了又很影响体验。
总结
Vue.nextTick其实是Vue内部为满足一些特殊业务场景而暴露出的一个API,它可以保证我们的某些操作针对的一定是更新后的页面,熟练的使用在某些场景下可以简化我们的业务实现逻辑哦。
感觉还可以的话,留下小心心慰藉一下小秃的“小秃头”吧~
转载自:https://juejin.cn/post/7239897512906113061