微信小程序的骨架屏:指页面的一个空白版本,通常会在页面完全渲染之前,通过一些灰色的区块大致勾勒出轮廓,待数据加载完成后,再替换成真实的内容。 抖音小程序的骨架屏:框架在页面真正渲染前先展示"灰块轮廓",显著缩短白屏时长、提升 LCP;时机早于业务手写骨架。
一、微信小程序
js
//在页面wxml引入模板并用wx:if控制
<import src="index.skeleton.wxml"/>
<template is="skeleton" wx:if="{{loading}}" data="{{}}"/>
//在页面 wxss 引入样式
@import "index.skeleton.wxss";
- 显隐控制:和普通模板一致,用
wx:if/hidden等。 - 生成配置:
project.config.json里通过skeletonConfig控制灰块规则、局部显示、过滤等(页面配置可覆盖全局)。 - 示例:
js
//```json
{
"skeletonConfig": {
"global": {
"outline": { "remain": false, "replace": "none" },
"text": { "color": "#EEEEEE" },
"image": { "color": "#EFEFEF" },
"remove": [],
"hide": [],
"grayBlock": [".btn", ".banner"],
"mode": "fullscreen",
"cssUnit": "rpx",
"decimal": 4
}
}
}
高级标注(可选):通过data-skeleton-*增强生成质量
data-skeleton-bgColor指定块背景色data-skeleton-list或data-skeleton-li="group"识别列表与克隆第一项data-skeleton-hide="key"让局部骨架渐进显示(与真实内容重叠时配合绝对定位)- 注意事项:
- 仅覆盖首屏可见区域;
swiper超出屏幕部分忽略 - 原生组件(video/map/input等)骨架效果受限
- 不要手改生成文件;调配置重新生成更稳
- 仅覆盖首屏可见区域;
- 文档参考:微信开发者工具 · 骨架屏
二、抖音小程序
- 形态与文件:每个页面对应一个 *.sk 模板文件,包含:
- template:仅支持 div + id/class/style
- style:标准 CSS
自动生成
1.在 IDE 3.2.6+,预览到目标页面 → 左下角选择列表 → 生成骨架屏 2.选择"保留/覆盖",可"自动引入"把 skeleton 配置写入 app.json/page.json 3.会在该页面同级生成 页面名.sk,可微调样式
- 配置入口 1.全局:app.json["skeleton"]["config"] 2.页面:page.json["skeleton"]["config"](优先级更高) 3.常用字段:loading(spin/chiaroscuro/shine)、image(shape rect/circle, color)、button.color、backgroundColor、mode(fullscreen/auto)、cssUnit(px/rem/vw/vh/...)、decimal
- 显示/隐藏 默认加载后 2000ms 自动隐藏;可在 timeout 调 0 关闭自动隐藏。 主动隐藏:this.removeSkeleton && this.removeSkeleton()(需在页面上下文) 局部隐藏:this.removeSkeleton({ id: 'node-id' }) 自定义导航栏适配(CSS 变量,2.51.0+): 可用 --status-bar-height、--menu-button-top、--menu-button-height、--pixel-ratio 等,结合 var()/calc() 计算布局。
注意与限制(官方提示):
- 仅首屏可见区域;超出屏幕的 swiper 子项会被忽略
- id 不能作为 CSS 选择器使用;原生/复杂组件效果有限
- 生成骨架包含预览态数据(文案等)用作填充
- 页面加载完成后再点击"生成骨架屏",效果更稳
- 文档来源:抖音小程序 · 框架骨架屏
三、在uni-app 中用"微信文档风格"实现骨架屏(两种方案)
方案A:复用微信骨架文件(推荐用于仅 MP-WEIXIN) 目标:保留官方生成逻辑,又能在 uni-app 中稳定使用、不被构建覆盖。
步骤:
- 1.在微信开发者工具里对目标页面(例如
pages/theater/theater)生成骨架,拿到theater.skeleton.wxml/wxss。 - 2.将这两个文件改造成"原生自定义组件"(避免每次构建被覆盖):
- 新建目录:
src/native-wx/skeleton/theater/ - 保存为
index.wxml(把skeleton.wxml内容整体作为组件模板),index.wxss(原样复制) index.json
index.json
{ "component": true, "usingComponents": {} }
- 3.在
pages.json为对应页面注册原生组件(仅微信端):
json
{
"path": "pages/theater/theater",
"style": {
"navigationBarTitleText": "剧场",
"usingComponents": {
"skeleton-view": "/native-wx/skeleton/theater/index"
}
}
}
若需要条件编译,仅在微信端生效,可把这个 usingComponents 放到微信专用的页面配置块里或用分平台 pages.json。
- 4.在
pages/theater/theater.vue中使用(切记仅微信端显示):
vue
<template>
<view class="theater">
<!-- #ifdef MP-WEIXIN -->
<skeleton-view v-if="loading" />
<!-- #endif -->
<view v-else>
<!-- 真实内容 -->
</view>
</view>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
const loading = ref(true)
onMounted(async () => {
// 拉数据...
loading.value = false
})
</script>
要点:
- 不要把骨架 wxml/wxss 放 dist 目录;构建会覆盖。放在
src/native-wx/并通过 usingComponents 引用最稳。 - 骨架本身是"原生组件",仅适用于 MP-WEIXIN;其他端会被条件编译屏蔽。
方案 B:跨端 Vue 骨架组件(更通用)
目标:一个组件多端通用,不依赖微信骨架生成器。
步骤: 1.新建 src/components/SkeletonTheater.vue,写占位块(方块、圆形、文本条)+ 闪动骨架 CSS:
SkeletonTheater.vue
<template>
<view class="skeleton" v-if="loading">
<view class="skeleton-banner shimmer" />
<view class="skeleton-card shimmer" v-for="i in 3" :key="i" />
</view>
</template>
<script setup lang="ts">
defineProps<{ loading: boolean }>()
</script>
<style scoped lang="scss">
.skeleton { padding: 24rpx; }
.shimmer {
position: relative; background: #eee; overflow: hidden;
}
.shimmer::after {
content: ""; position: absolute; inset: 0;
transform: translateX(-100%); background: linear-gradient(90deg, transparent, rgba(255,255,255,.5), transparent);
animation: shimmer 1.2s infinite;
}
@keyframes shimmer { 100% { transform: translateX(100%); } }
.skeleton-banner { height: 300rpx; border-radius: 16rpx; }
.skeleton-card { height: 160rpx; margin-top: 24rpx; border-radius: 16rpx; }
</style>
在页面中使用:
vue
<SkeletonTheater :loading="loading" />
<view v-if="!loading"> ...真实内容... </view>
要点:
- 完全跨端;不依赖微信文件格式,也无需
usingComponents。 - 若页面复杂,可拆分多个骨架组件,随不同请求的返回逐块替换。
实战建议与坑位 控制粒度:只覆盖"首屏可见区域",骨架越轻越好,降低首屏 CSS/节点体积。 loading 状态来源:首屏必要数据(如 banner/列表)全部到齐再切换;避免频繁闪烁。 与你现有样式规范: 组件内避免使用全局标签选择器(page/view/text 等),符合微信组件 WXSS 限制(你之前已踩过这个错误)。 骨架组件样式尽量 scoped,避免污染。 与 Loading 的配合: 骨架与 uni.showLoading/uni.hideLoading不冲突。建议首屏只用骨架,不弹系统 loading,避免"跳转后 hideLoading 报错"的问题。 结合 skeletonConfig 再生成:当页面结构变化时,可通过调整 project.config.json 后重新生成骨架,再覆盖到 src/native-wx/skeleton/... 组件中,保持一致性。
在uni-app(MP-TOUTIAO)中落地的建议 最省心路径(推荐)
- 1.用抖音 IDE 对 dist 下的对应页面生成 *.sk 并"自动引入",无需改 .vue;页面结构变化后再生成一次保持同步
- 若要在代码中"主动隐藏"骨架(可选):
- 在该 uni-app 页面里(onReady/数据到齐时)取原生 Page 实例后调用:
js
import { onReady } from 'vue'
onReady(() => {
const pages = getCurrentPages()
const page = pages[pages.length - 1] as any
page?.removeSkeleton && page.removeSkeleton()
// 局部:page?.removeSkeleton && page.removeSkeleton({ id: 'node-id' })
})
配置示例(自动生成时 IDE 会写入):
json
{
"skeleton": {
"page": "pages/your-page/index",
"config": {
"loading": "shine",
"image": { "shape": "rect", "color": "#efefef" },
"button": { "color": "#efefef" },
"backgroundColor": "#fff",
"mode": "fullscreen",
"cssUnit": "vw",
"decimal": 4,
"timeout": 0
}
}
}
说明:将 timeout 设为 0 后,需手动调用 removeSkeleton() 隐藏;若不需要手动控制,可保留默认超时隐藏。
选型对比与实践建议:
- 需要"极致首屏体验"且目标端是抖音:优先用框架骨架屏(
*.sk+ skeleton 配置),注入时机更早。 - 需要多端统一:可额外做一套 Vue 骨架组件(跨端可复用),但首屏时机会稍晚;抖音端同时开启框架骨架屏可叠加优化。
- 与系统 loading 并用:建议首屏显示骨架,避免频繁调用系统
showLoading/hideLoading造成跳转后报错或闪烁。
建议(结论先行)
- 优先用自动生成(框架级骨架屏):目标端是微信/抖音,追求最早展示时机与更好 LCP 表现,且页面改动较频繁。
- 补充用手写(业务级骨架组件):需要跨端统一(uni-app 多端共用)、样式高度自定义、或做局部骨架/渐进加载的页面片段。
何时选自动生成
-
只面向 MP-WEIXIN / MP-TOUTIAO,且是首屏关键页(如剧场、播放器):框架骨架注入更早,体验最佳。
-
页面结构经常变化:用工具一键再生,维护成本低。
-
抖音可直接生成 *.sk 并通过 app.json/page.json 的 skeleton 注入;微信用工具生成 page.skeleton.wxml/wxss 引入即可。
-
支持主动/局部隐藏:this.removeSkeleton() / this.removeSkeleton({ id }),能配合数据就绪精准消失。
-
微信文档参考:骨架屏(开发者工具)
-
抖音文档参考:框架骨架屏
何时选手写
-
需要跨端(H5、App、抖音、微信)复用同一骨架,或希望在组件维度复用(如通用列表骨架、卡片骨架)。
-
复杂的自定义动效/布局、或与业务占位强绑定(如占位图、品牌样式统一)。
-
希望避免"生成文件随页面结构频繁再生"的流程。
对你项目的具体建议
-
pages/theater/theater、pages-toutiao/playlet/index:用自动生成(各自端启用框架骨架),并把超时隐藏设为 0,数据到齐后主动移除,避免闪烁。
-
通用组件位(如列表卡片骨架):补一套手写的 Vue 骨架组件,供其他页面/端复用,保持风格一致。
一句话:首屏关键页用"自动生成"拿极致加载时机;通用组件/跨端一致性用"手写"兜底,两者组合最佳。
ly带你手把手来骨架屏:

- 点击页面信息,然后点击生成骨架屏,弹出下面这段话,直接确定就可以了。

注意:骨架屏仅包括页面首屏中的可见区域,对于横向滚动的 swiper 等容器,超出屏幕的子元素将被忽略;
转成vue组件
- 1.处理theater.skelecton.wxml
拷贝theater.skelecton.wxml文件的内容,然后到vscode中的uniapp应用中,生成一个新的PageSkeleton.vue,将theater.skelecton.wxml文件的内容粘贴进去。
文件开头的注释是针对在原生微信小程序中如何操作的提示,在uni-app中不需要这样操作,可以删掉这些注释。

页面中自定义导航看部分不涉及数据请求,所以不需要放在骨架屏中,因为骨架屏是针对要请求数据而暂时没有返回时的用户体验提升,所以吧这部分删掉。
可以改一下动态属性
处理样式文件

把wxss样式添加到这个PageSkeleton.vue页面去。


结构和样式都准备完之后,在首页根据数据加载是否完成条件骨架屏。
在首页先引入骨架屏文件。 改造首页页面插入骨架屏文件,然后条件显示。



小朋友们:看抖音怎么玩,找出来骨架屏



点击确定
勾选「自动引入 」,表示将在 app.json 中生成 skeleton 配置,不勾选则不作处理。生成配置如下:
确定后将在当前页面同级目录下生成 *.sk文件( 表示页面名称 ),文件内包括骨架屏的代码模板以及样式,开发者可以修改调整。

