原因
先看一段简单、常规的vue代码。
<template>
<div v-if="list && list.length>0">
<div v-for="row in list">
<span>{
{row.xxx}}</span>
//显示剩下数据
</div>
</div>
<div v-else>
<div>暂无数据</div>
</div>
</template>
<script>
export default {
created() {
this.ajaxform('/chronic/xxx').then(res => {
this.list = res.body
})
}
}
</script>
这段代码在created生命周期函数内会调用后端接口获取数据,我们假设获取数据的时间需要1秒。那么打开页面后将显示“暂无数据”,1秒后才会显示列表数据,给客户的体验有些不好。这篇文章就来解决这个打开页面先显示暂无数据的问题。
思路
我们希望能加入一个过渡状态,在ajax请求加载数据时显示“数据加载中”,数据加载完成后再根据有无数据来显示列表或是“暂无数据”。当跳转页面时,流程如下图:
但不能所有的ajax请求都显示数据加载中,只能是打开页面后立即执行的ajax请求显示加载中,也就是created、mounted中执行的ajax请求显示加载中。
方案
首先我们需要一个全局变量来储存当前正在执行的ajax请求的数量以及是否是页面刚打开的状态。我将这两个变量存在了store中
const state = {
pageInit: false,
// 记录有几个ajax请求正在执行中
ajaxCount: 0,
}
const mutations = {
updatePageInit: function (state, pageInit) {
state.pageInit = pageInit
},
updateAjaxCount: function (state, count) {
state.ajaxCount = state.ajaxCount + count
}
}
export default {
namespaced: true,
state,
mutations
}
然后因为项目中发起ajax请求的组建使用的是axios,所以可以在axios的request、response拦截器中,对这个数进行加减。请求开始,则对ajaxCount加1,请求成功或是失败对ajaxCount减1
axios.interceptors.request.use(
config => {
store.commit('user/updateAjaxCount', 1)
return config
},
error => {
store.commit('user/updateAjaxCount', -1)
return Promise.reject(error)
}
)
axios.interceptors.response.use(
response => {
store.commit('user/updateAjaxCount', -1)
return response
},
error => {
store.commit('user/updateAjaxCount', -1)
return Promise.reject(error)
}
)
在router的afterEach函数中对pageInit的值进行更新,也就是设置为刚打开页面的状态
router.afterEach(function (to, from) {
store.commit('user/updatePageInit', true)
})
再然后在App.vue中要做两件事情
1、在template中,通过私有变量loading的值显示、隐藏<router-view>和加载状态(菊花动图)。
2、对ajaxCount进行watch,当ajaxCount大于0,且是刚进入页面的状态时,设置私有变量loading为true,显示加载中状态。
当ajaxCount等于0时,也就是ajax请求全部结束时,设置私有变量loading为false,关闭加载中状态,设置pageInit为false,显示数据。
<template>
<div style='height:100%;'>
<router-view v-show="!loading"></router-view>
<div v-show="loading"><img src="xxx/juhua.gif"></div><!-- 转菊花的动图 -->
</div>
</template>
<script>
export default {
name: 'app',
data () {
return {
loading: false
}
},
computed: mapState({
pageInit: state => state.user.pageInit,
ajaxCount: state => state.user.ajaxCount
}),
watch: {
ajaxCount (count) {
// count>0表示有ajax请求正在执行中, pageInit表示刚进入新页面, loading表示菊花转的状态
if (count > 0 && this.pageInit && this.loading === false) {
this.loading = true
}
if (count === 0) {
this.loading = false
this.$store.commit('user/updatePageInit', false)
}
}
}
}
</script>
以下是效果图,第一张加载中状态是转菊花的图,第二张加载中状态是骨架屏的图
结语
我们加载中状态显示的很简单,只是转菊花,这里也可以做的效果更好一些,例如骨架屏等。