骨架屏必须用 v-show 控制显隐,因其需常驻 DOM 以维持布局稳定;v-if 会导致节点销毁重建,引发页面闪烁、滚动丢失及首屏节奏破坏。

骨架屏该用 v-show 还是 v-if 控制显隐
必须用 v-show。骨架屏本质是「占位」,不是条件渲染——它要和真实内容共存于 DOM 中,才能保证布局不跳动、尺寸不塌陷。一旦用 v-if,骨架节点被销毁,真实内容加载后重新挂载,页面会闪一下,滚动位置也可能丢失。
常见错误现象:下拉刷新后骨架一闪就消失,但内容没对齐;或在 iOS WebView 中出现白屏抖动。
-
v-show只切display: none,DOM 结构始终存在,CSS 骨架样式能持续生效 -
v-if会触发组件销毁/重建,onLoad等生命周期重走,破坏首屏加载节奏 - 如果骨架是独立组件(如
SkeletonCard.vue),确保其props不含响应式依赖,否则v-show下仍可能触发无谓更新
uni-app 的 onReady 和 onLoad 哪个时机关骨架屏
关骨架屏的逻辑必须放在 onReady 之后,且要等真实数据渲染完成——不能只等接口返回,得等 this.$nextTick()。
使用场景:列表页请求 API 后赋值 this.list,但直接 this.loading = false 会导致骨架消失时 DOM 还没更新,视觉上还是空白几帧。
- 错误写法:
api().then(() => { this.loading = false })—— 数据已赋值,但视图未刷新 - 正确顺序:
api().then(() => { this.list = res; this.$nextTick(() => { this.loading = false }) }) - 兼容性注意:H5 端
$nextTick可靠;小程序端(尤其微信)若用了自定义组件嵌套,建议加setTimeout(..., 16)保底,避免极少数机型渲染延迟
骨架屏 CSS 在不同平台表现不一致怎么办
核心矛盾是 uni-app 编译后各端对伪元素、动画、渐变的支持差异大。比如 background-image: linear-gradient(...) 在 App 端(iOS WKWebView)常失效,导致骨架“没颜色”;animation 在支付宝小程序里不触发。
参数差异:H5 支持完整 CSS 动画;微信小程序仅支持部分属性动画;App 端需额外加 -webkit- 前缀才生效。
- 统一用
background-color+opacity模拟“闪烁”效果,比渐变更稳:background-color: #f0f0f0; animation: pulse 1.5s infinite; - 动画定义必须写在
/* #ifdef H5 */或/* #ifdef APP-PLUS */条件编译块里,避免小程序报错 - 避免用
::after绘制骨架线条——某些低端安卓机上伪元素渲染异常,改用空<view></view>+height/width更可控
如何让骨架屏适配 dark mode
uni-app 本身不提供系统级暗色监听,得手动读取 uni.getSystemInfoSync().theme(仅微信/支付宝支持),或依赖 CSS 自定义属性 + 页面 class 切换。
性能影响:每次切换主题都重绘骨架会卡顿,所以推荐初始化时一次性判断,后续不响应变化。
- 在
mounted或onLoad里执行:const theme = uni.getSystemInfoSync()?.theme || 'light' - 骨架组件内用
:class="['skeleton', theme === 'dark' ? 'skeleton-dark' : '']" - 不要在
computed里动态读取theme——小程序不支持theme实时变更,且频繁读取getSystemInfoSync有性能开销
骨架屏最难的从来不是怎么画,而是“什么时候收、在哪收、收完还稳不稳”。很多问题出在把骨架当成 loading,其实它是布局契约——只要 DOM 一动、样式一抖、时机一错,用户就感知到了。










