uni-app骨架屏必须手写,因小程序平台不走dom流程,插件依赖的webpack ast分析或运行时dom注入失效;v-if会销毁节点导致重排闪屏,故须用v-show保结构稳定。

uni-app骨架屏为什么必须手写,不能用插件
所有声称“一键生成”的插件(比如uni-skeleton、vue-skeleton-webpack-plugin)在小程序平台基本失效。原因很实在:uni-app编译到微信小程序时,不走标准 DOM 流程,而是生成 .wxml + .wxss;插件依赖 Webpack AST 分析或运行时 DOM 注入,根本找不到节点下手。
更麻烦的是,自动生成的 .wxml 骨架结构直接搬进 .vue 文件后,常出现三类问题:
-
uni.createSelectorQuery查不到未渲染的骨架节点,导致后续逻辑(如滚动定位、尺寸测量)失败 - slot 或动态 props 在
v-show下仍触发响应式更新,拖慢首次渲染 - 百分比宽高、flex 布局在小程序中计算不稳定,骨架和真实内容错位
用 v-show 还是 v-if 控制骨架显隐
必须用 v-show,不是 v-if。骨架屏本质是占位,不是条件分支。
v-if 会让骨架节点被彻底销毁,等数据回来再挂载真实内容时,触发完整 DOM 重建和重排——iOS WebView 中常见滚动位置丢失、页面“闪一下再跳出来”;而 v-show 只切 display: none,DOM 结构稳定,CSS 动画过渡顺滑,也方便配合 $nextTick 精确控制切换节奏。
关键操作点:
- 骨架结构提前写死在模板里,不要包裹在
v-if中 - 响应式变量命名建议统一为
loading,初始值设为true - 在
uni.request调用前就设this.loading = true,不是等 success 回调才设
怎么避免骨架屏“一闪就消失”或“白屏穿帮”
最常见现象是:新页面刚进入,接口秒回,loading = false 立刻执行,结果用户看到「骨架 → 白屏 → 内容」三段式。这不是动画问题,是生命周期没对齐。
正确做法是卡住两个时间点:
- 显示时机:在
onLoad或onShow开头就设this.loading = true,别等请求发出去才动 - 隐藏时机:接口返回后先赋值(如
this.list = res.data),再this.$nextTick(() => { this.loading = false }) - 加保底延时:小程序端建议补一句
setTimeout(() => { this.loading = false }, 16),防$nextTick失效 - 强制最小展示:哪怕数据立刻回来,也要撑住至少 300ms,用
setTimeout(() => { this.loading = false }, 300)
跨平台动画怎么写才不崩
H5、小程序、App 对 CSS 动画支持差异大,不能一套代码打天下。
H5 端可放心用 linear-gradient + background-position 动画模拟扫描光效;但微信小程序不支持 background-image 动画,得换成 transform 移动色块方案;App 端虽支持 transform,但骨架里嵌太多 <text></text> 或 <image></image> 会触发重绘卡顿。
实操建议:
- 图片占位必须用
<image mode="scaleToFill"></image>,禁用<view></view>+ background,否则真图加载完成会 layout shift - 所有尺寸用
rpx或固定px,禁用百分比宽高 - 颜色统一用
#f2f2f2(背景)和#e4e4e4(色块),规避暗黑模式翻车 - 列表页按区块写,比如 3 行
<view class="skeleton-item"></view>,别堆 20 个空<view></view>
真正难的不是写出骨架,而是让骨架和数据流、生命周期、平台限制严丝合缝咬在一起。漏掉任意一环,它就会从优化手段变成体验破绽。











