等待感从哪来:骨架屏要解决的问题
用户对慢的感知,往往不是来自「真的慢」,而是来自「不知道要等多久」。一个白屏干等三秒,和一个带着占位骨架的过渡三秒,主观感受天差地别。骨架屏要解决的,就是把这段空白等待变成一次有结构、可预期的过渡。
骨架屏的思路很朴素:数据还没回来,先把页面的轮廓画出来。用灰色块占位标题、图片、列表的位置,等数据到了再无缝替换成真实内容。用户看到的是页面「逐渐被填满」,而不是从空白突然蹦出一堆字。
好的加载体验不是让人等得更短,而是让人等得不慌。
本文核心知识点
- 骨架屏用占位块预渲染页面轮廓,消除白屏焦虑。
- 预加载在合适的时机提前拉数据,等用户点开时数据已就绪。
- 分层缓存把数据按新鲜度分档,弱网下优先用旧数据兜底。
- 降级弱网或失败时给出明确反馈,而不是无限转圈。
骨架屏的两种实现方式
落地骨架屏,常见有两条路。一条是在页面里手写一套占位结构,数据到位后切换显示;另一条是借助组件或自动化工具,根据真实结构生成占位。对中小项目,手写一套往往更可控。
// 列表页骨架屏:用 loaded 标志切换占位与真实列表
data() {
return { loaded: false, list: [] };
},
onLoad() {
wx.request({ url: "/api/list" }).then(res => {
this.setData({ list: res.data, loaded: true });
});
}
骨架屏的关键不是「有占位」,而是占位要长得像真页面:
- 占位块的位置、高度、圆角和真实卡片对齐,切换时才不跳。
- 给骨架加一点轻微的呼吸动画,告诉用户「在动」。
- 占位的条目数按实际列表长度估,别写死。
切换那一刻是体验的分水岭:如果骨架和真实内容对不齐,替换时页面会抖一下,前面的努力就白费了。
预加载与数据预热
骨架屏只是把等待变好看,预加载才是真正把等待变短。思路是:在用户还没点进去之前,就把下一页的数据先拉回来。
// 首页 onShow 时,顺手预拉详情页会用到的公共数据
onShow() {
if (!wx.getStorageSync("hotReady")) {
wx.request({ url: "/api/hot-list" }).then(res => {
this.setData({ hotList: res.data });
wx.setStorageSync("hotReady", true);
});
}
}
几个分寸要拿捏好:
- 预加载只做用户「大概率下一步」会用到的数据,别什么都抢。
- 把预加载放在页面空闲时机,别和首屏渲染抢资源。
- 预拉的数据放进缓存,下次进入直接命中,连请求都省了。
缓存策略:分层与过期
弱网体验的核心,是「即使网不好,也能给用户看到点东西」。这就要求你对不同数据采用不同的缓存策略,而不是一刀切每次都重新请求。
| 数据类型 | 新鲜度要求 | 缓存策略 |
|---|---|---|
| 用户个人信息 | 高 | 进入时刷新,本地仅兜底 |
| 列表内容 | 中 | 缓存几分钟,过期后台静默更新 |
| 字典/配置 | 低 | 长缓存,版本号变化才更新 |
// 带过期时间的缓存读取:先给旧数据,后台再悄悄更新
function getCached(key, fetchUrl) {
const hit = wx.getStorageSync(key);
if (hit && (Date.now() - hit.time) < 5 * 60 * 1000) {
return hit.data; // 缓存未过期,直接用
}
wx.request({ url: fetchUrl }).then(res => {
wx.setStorageSync(key, { data: res.data, time: Date.now() });
});
return hit ? hit.data : null; // 过期则先返回旧的兜底
}
这套「先旧后新」的模式,是弱网体验的精髓:用户永远先看到内容,新鲜度由后台悄悄补齐。
弱网下的降级与兜底
再好的缓存也有缓存空的时候——第一次打开、数据过期又完全断网。这时候要明确告诉用户「现在不行」,而不是让一个 loading 无限转下去。
- 超时要短:请求设一个合理超时,别让用户干等二十秒。
- 失败要友好:给出「网络不太顺,点我重试」,而不是一句冰冷的报错。
- 有旧数据就展示旧数据,上面标一句「内容更新于某时」。
wx.request({ url: "/api/list", timeout: 8000 })
.then(r => render(r.data))
.catch(() => {
this.setData({
showError: true,
fallback: wx.getStorageSync("listCache") || null
});
});
把「空态、加载态、错误态」这三种状态都设计好,弱网体验才算真正闭环。
加载态与错误态的细节
体验的差距,往往藏在这些没人写进文档的细节里。
- 下拉刷新时,别让骨架屏和真实列表同时出现。
- 分页加载下一页用底部小条,不要整页转圈打断阅读。
- 成功的反馈要轻,失败的反馈要重——区分清楚。
- 重试按钮要有防抖,别让用户连点十次发十个请求。
这些细节单独看都很小,但叠加起来就是用户觉得「这个小程序顺不顺手」的全部依据。
一套可落地的加载清单
把前面的内容收成一份能直接对着做的清单。
- 首屏:骨架屏占位对齐真实结构,加载完无缝替换。
- 下一步:高频跳转的数据做预加载并缓存。
- 数据:按新鲜度分档缓存,弱网先旧后新。
- 失败:短超时、友好重试、有旧数据就兜底。
- 状态:空、加载、错误三态都画清楚。
弱网体验不是「让网变快」,而是「让慢变得可接受」。