vue异步获取数据解析
最近在用vue重构有赞商城,在异步获取数据的时候有些困惑,所以总结分享给大家,也希望大家能够一起进步。
场景显示: 我们现在需要做一个轮播组件,我们需要接收父组件传递过来的图片数组(lists),所以父组件需要请求后端接口,从而获取数组列表。
1. 数据变化
数据流程.png数据的到来分几步阶段 list: null
- 通过接口异步请求数据 loading状态
- 获取回来的数据:
- 有数据 渲染 list&&list.length > 0
- 无数据 空状态的提示 list&&list.length = 0
父组件初始化要获取的lists数组
// 父组件
data(){
return {
lists : null
}
},
created() {
this.getBanner()
}
methods: {
getBanner() {
// 获取数据
axios.get(url.banner).then((res) => {
this.lists = res.data.lists || [];
})
}
}
2. 子组件接收数据的过程
子组件接收父组件的数据
- 当异步请求还没有得到数据的时候,得到
lists = null
- 当异步请求得到数据后,通过props,才能够得到真正的数据 。
这里就有一个问题了
- 父组件刚开始传递的数据是null给子组件,但是子组件期望得到的是一个数组
解决方案: 当list=null
的时候不渲染子组件,当数据到来的时候再进行渲染子组件
// 数据到来的时候渲染子组件
<swiper :lists= bannerLists name="swiper-banner" v-if="bannerLists"></swiper>
// 数组没有到来的时候loading
<div v-else>loading</div>
子组件的代码:
props: {
lists: {
type: Array,
required: true
},
// lists: {},
name: {}
},
// swiper必须要依赖dom
mounted() {
this.init();
},
methods: {
init() {
new Swiper('.swiper-container',{
loop: true,
pagination: '.swiper-pagination',
autoplay: 2000
})
}
},
解决方案: 如果我们不通过v-if来判定子组件是否渲染,而是通过子组件的生命周期函数进行处理
props: {
//lists: {
//type: Array,
//required: true
//},
lists: {}, //不能限定type,接收刚开始的null,和之后的数组lists
name: {}
},
// swiper必须要依赖dom
methods: {
init() {
new Swiper('.swiper-container',{
loop: true,
pagination: '.swiper-pagination',
autoplay: 2000
})
}
},
watch: {
//监听lists的变化(从null => 数组)
lists(val,oldVal) {
this.nextTick(() => {
this.init() //当数据到来的时候, DOM 更新循环结束之后,立即执行函数
})
}
}
解析: 这里为什么需要使用this.nextTick()
呢?当我们监听到lists发生变化的时候,数据虽然到来了,但是通过数据渲染到的对应dom还没有执行,我们还不能获取到对应的dom,只能通过异步的方式处理(this.nextTick())
<template>
<div class="swiper-container">
<div class="swiper-wrapper">
<div class="swp-page swiper-slide" v-for="list in lists">
<a class="js-no-follow" :href="list.clickUrl">
![](list.image)
</a>
</div>
</div>
<div class="swiper-pagination"></div>
</div>
</template>
<script>
watch: {
lists(val,oldval){
console.log(document.querySelector('.swiper-container')) //可以获取
console.log(`val++++${val}`);
console.log(document.querySelectorAll('.swiper-slide')) //不能获取
this.$nextTick(() => {
if(val){
this.init();
}
console.log(document.querySelectorAll('.swiper-slide')) //可以获取
})
}
}
</script>
要确定dom已经渲染完毕,如果有初始数据,在mounted这个阶段dom已经渲染完毕。如果通过watch来监听数据的变化,数据变化后不是马上渲染dom的,是等到下次事件队列来处理的,就需要用到nextTick。
关于nextTick可以查看
网友评论