uni-app 骨架屏无法靠插件自动生成,因其缺乏构建时 AST 分析能力,小程序平台不支持自定义指令和运行时 DOM 注入,跨端渲染差异大,手动编写轻量骨架组件并用 hidden 控制显隐最稳定。

uni-app 里骨架屏为什么不能靠插件自动生成
uni-app 没有类似 Vue CLI 的构建时 AST 分析能力,vite-plugin-skeleton 或 vue-skeleton-webpack-plugin 在 H5 端可能勉强跑通,但到了小程序平台(尤其是微信、支付宝)直接失效——因为编译器不识别自定义指令或运行时注入的 DOM 节点,uni.createSelectorQuery 也拿不到未渲染的骨架结构。
常见错误现象:Cannot read property 'querySelector' of null、骨架图在真机上完全不显示、H5 正常但小程序白屏。
- uni-app 的
pages.json静态配置 +render函数动态生成机制,天然排斥“自动扫描模板生成骨架”的思路 - 跨端一致性要求高:微信小程序的
view和 H5 的div渲染差异,导致同一份骨架组件在不同平台表现不一致 - 性能陷阱:试图在
onLoad里异步请求数据前插入骨架,但setData或this.$nextTick延迟会导致闪动更明显
用 skeleton 组件手动写才是最稳的路径
所谓“自动生成”,实际是开发者按页面结构手写一份轻量级骨架模板,再用条件控制显隐。这不是倒退,而是适配 uni-app 多端机制的必然选择。
使用场景:列表页(uni-list)、详情页(带头图 + 多段文本)、表单页(输入框 + 按钮)。
- 骨架组件必须用
<template>写,避免data响应式开销;用props控制是否显示(如loading),而非v-if切换整个结构 - 不要用
uni.showLoading替代骨架——它不占位,内容加载后会“突然顶上来”,体验更差 - 颜色统一用
#f2f2f2(灰色背景)和#e4e4e4(色块),避免在暗黑模式下翻车 - 示例片段:
<template> <view class="skeleton-wrapper" v-if="loading"> <view class="skeleton-avatar"></view> <view class="skeleton-title"></view> <view class="skeleton-paragraph"></view> </view> </template>
onShow 时机比 onLoad 更适合触发骨架显隐
很多页面从 tabBar 切入时,onLoad 不执行,但数据要重拉——如果只监听 onLoad,骨架就不会出现,用户看到的是空白页。
参数差异:onLoad 只在首次进入页面时触发;onShow 每次页面显示都触发(含从后台切回、tabBar 切换)。
- 把骨架显隐逻辑放到
onShow,配合uni.getStorageSync判断缓存是否存在,决定是否立即显示骨架 - 网络请求发完立刻
this.loading = true,而不是等uni.request的success回调才设为false——否则骨架一闪就没了,起不到占位作用 - 避免在
onPullDownRefresh里漏掉this.loading = true,否则下拉刷新时骨架不出现
小程序平台要特别注意 hidden 和 v-show 的兼容性
微信小程序基础库 2.25.0+ 支持 v-show,但低版本仍需用 hidden。uni-app 编译时不会自动降级,写错就白屏。
性能影响:用 v-if 会卸载 / 重建 DOM,比 v-show 或 hidden 开销大得多,骨架频繁切换时卡顿明显。
- 统一用
hidden="{{!loading}}"(小程序语法)或:hidden="!loading"(Vue 模式),别混用v-show - H5 端可放心用
v-show,但若项目需兼容旧版微信(如 2.20.0),就得全局用hidden - 检查
manifest.json中的最低基础库版本,低于 2.25.0 就别碰v-show
骨架屏不是加个插件就能跑起来的活,真正麻烦的是各端渲染机制的细微差别——比如微信小程序里 hidden 对 position: absolute 元素的处理,和 H5 完全不一样。这些细节不亲手试两轮真机,光看文档根本绕不过去。