Skeleton骨架屏在Vue中如何正确控制显示时机?
我在用Vue做列表页,数据从接口获取,想加个骨架屏提升体验。但不确定该在什么时候切换骨架屏和真实内容。
目前是用loading变量控制,初始为true,请求完成设为false。但有时候数据很快回来,骨架屏闪一下反而更突兀,有没有更平滑的方案?
这是我的模板结构:
<div v-if="loading">
<SkeletonItem v-for="i in 5" :key="i" />
</div>
<div v-else>
<Item v-for="item in list" :key="item.id" :data="item" />
</div>
你现在的做法是请求完立即切换loading状态,数据如果200ms就回来了,骨架屏只闪了200ms,视觉上就是突兀的一下。解决思路很简单——给骨架屏加个"最短显示时间",让它至少展示一段时间再切换。
最实用的方案是用一个延迟来控制切换时机。我给你改一下逻辑:
首先在data里加两个状态:
data() {
return {
loading: true,
// 记录骨架屏开始显示的时间戳
skeletonStartTime: null,
// 骨架屏最短显示时间,单位毫秒,建议300-500ms
minSkeletonDuration: 300
}
}
然后改造你的请求逻辑:
async fetchList() {
this.loading = true;
this.skeletonStartTime = Date.now();
const res = await api.getList();
// 请求完成后,计算已经显示了多久
const elapsed = Date.now() - this.skeletonStartTime;
const remaining = this.minSkeletonDuration - elapsed;
if (remaining > 0) {
// 如果还没达到最短显示时间,等剩余时间到了再切换
setTimeout(() => {
this.loading = false;
}, remaining);
} else {
// 已经超过最短时间了,立即切换
this.loading = false;
}
}
这个方案的原理很简单:骨架屏一旦显示,就记录开始时间,不管数据什么时候回来,都要保证骨架屏至少展示了300ms。这样即使用户网络很好,也不会出现闪烁问题。
如果想体验更好,还可以加个渐变过渡效果。Vue的transition组件就能搞定:
这样切换的时候是淡入淡出的,骨架屏慢慢消失,内容慢慢出现,体验比直接硬切换柔和很多。
最后提醒一点,最短显示时间别设太长,300-500ms就够了。太长的话网速慢的用户会等得烦躁,这个数值是个平衡点。