骨架屏

微信小程序的骨架屏:指页面的一个空白版本,通常会在页面完全渲染之前,通过一些灰色的区块大致勾勒出轮廓,待数据加载完成后,再替换成真实的内容。 抖音小程序的骨架屏:框架在页面真正渲染前先展示"灰块轮廓",显著缩短白屏时长、提升 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-listdata-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文件( 表示页面名称 ),文件内包括骨架屏的代码模板以及样式,开发者可以修改调整。

相关推荐
用户677847150628 小时前
前端将html导出为word文件
前端
前端付豪8 小时前
如何使用 Vuex 设计你的数据流
前端·javascript·vue.js
李雨泽8 小时前
通过 Prisma 将结构推送到数据库
前端
前端小万8 小时前
使用 AI 开发一款聊天工具
前端·全栈
咖啡の猫9 小时前
Vue消息订阅与发布
前端·javascript·vue.js
GIS好难学9 小时前
Three.js 粒子特效实战③:粒子重组效果
开发语言·前端·javascript
申阳9 小时前
Day 2:我用了2小时,上线了一个还算凑合的博客站点
前端·后端·程序员
刺客_Andy9 小时前
React 第四十七节 Router 中useLinkClickHandler使用详解及开发注意事项案例
前端·javascript·react.js
爱分享的鱼鱼9 小时前
Java实践之路(一):记账程序
前端·后端