Vue页面跳转优化,loading中间状态和骨架屏
原因
先看一段简单、常规的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>
以下是效果图,第一张加载中状态是转菊花的图,第二张加载中状态是骨架屏的图
结语
我们加载中状态显示的很简单,只是转菊花,这里也可以做的效果更好一些,例如骨架屏等。