Skeleton骨架屏在Vue中如何正确控制显示时机?

沐岩 Dev 阅读 8

我在用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>
我来解答 赞 1 收藏
二维码
手机扫码查看
1 条解答
Des.星瑶
这个问题的关键是:骨架屏闪一下的本质是显示时间太短,人眼还没来得及感知就切换了。数据越快回来,这个问题越明显。

你现在的做法是请求完立即切换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就够了。太长的话网速慢的用户会等得烦躁,这个数值是个平衡点。
点赞
2026-03-17 18:01