uni-app 小程序平台无法真正自动生成骨架屏,因编译器不识别运行时 DOM 注入;应使用 v-show 而非 v-if 控制显隐,onShow 替代 onLoad 管理 loading 状态,手写组件需适配暗黑模式、rpx 单位及纯 view/text 结构。

uni-app 无法真正“自动生成”骨架屏,所谓插件或工具链一键生成,在小程序平台(尤其是微信、支付宝)基本不可用——编译器不识别运行时注入的 DOM,vite-plugin-skeleton 和 vue-skeleton-webpack-plugin 在 H5 端可能凑合,但一打包到小程序就报错或直接不渲染。
为什么不能用 v-if 控制骨架屏显隐
常见错误是把骨架屏当普通条件组件,用 v-if="loading" 切换。这会导致 DOM 节点销毁重建,引发三类问题:
- 页面布局跳动:真实内容挂载时尺寸重排,用户看到“一闪一抖”
- 滚动位置丢失:特别是下拉刷新后,页面自动滚回顶部
- 生命周期紊乱:
onLoad重复触发,uni.createSelectorQuery查不到节点,动画中断
必须用 v-show。它只切 display: none,骨架节点始终在 DOM 中占位,CSS 样式持续生效,布局零干扰。
onShow 比 onLoad 更适合控制 loading 状态
很多开发者在 onLoad 里发请求、设 this.loading = false,结果从后台切回来或 tab 切换后骨架不显示——因为 onLoad 只执行一次。
-
onLoad:仅首次进入页面时触发 -
onShow:每次页面可见都触发(含冷启动、热切换、tabBar 切换)
正确做法是:data 里初始化 loading: true,在 onShow 中立即发起请求,并在 uni.request 的 complete 或 finally 钩子里设 this.loading = false。不要等 success——网络失败时骨架会永远卡住。
手写骨架组件要注意颜色与暗黑模式兼容
直接抄 #ebebeb 或 #f0f0f0 容易翻车。iOS 微信 WebView + 暗黑模式下,浅灰背景会变成刺眼亮白,色块和文字对比度崩坏。
- 统一用
#f2f2f2(背景) +#e4e4e4(色块),这两个值在明/暗模式下视觉一致性最强 - 避免用
image模拟头图占位——小程序不支持background-image,且image加载失败会留空白边框 - 圆角统一用
8rpx或10rpx,别写4px,否则多端缩放错乱
示例中 .card-placeholder 的 height: 150px 应改为 150rpx,否则在 iPhone Plus 类设备上会被拉长变形。
微信开发者工具生成的 .wxml/.wxss 不能直接塞进 .vue
有人把微信工具导出的 skeleton.wxml 复制进 Skeleton.vue 的 ,结果真机白屏或样式错位——原因有二:
- 微信原生
语法 uni-app 不识别,必须手动删掉所有is=""属性 - 原生
.wxss里的width: 100%在嵌套下常失效,需补flex: 1或显式设width: 750rpx
更稳妥的做法:把生成的结构当参考,用纯 + 重写,样式全走 scoped CSS,不依赖任何平台特有语法。
最易被忽略的一点:骨架屏组件内部不要传入响应式数据(比如 :list="realList"),哪怕只是用来控制 v-for 次数。v-show 下它仍会监听变化并触发重绘,造成无谓性能损耗。用 props 传静态数量(如 lines: 5)最干净。











