news 2026/10/9 7:46:53

boneyard-js 骨骼屏生成框架实战指南:DOM 快照转矩形 Bones 的多框架 Skeleton 方案

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
boneyard-js 骨骼屏生成框架实战指南:DOM 快照转矩形 Bones 的多框架 Skeleton 方案

【免费下载链接】boneyard

Auto generated skeleton loading framework

项目地址:https://gitcode.com/gh_mirrors/bo/boneyard
点击查看免费下载

导读

本文以 boneyard 仓库中《Boneyard Skeleton Skill》文档为主体,系统讲解boneyard-js——一个把真实 UI 快照成带定位矩形 "bones"(骨骼)的骨架屏生成器。你将掌握:bones 数据格式与解析优先级、boneyard.config.json全部配置项、CLI 构建与 Vite 插件工作流、React/Svelte/Vue/Angular/Preact/React Native 多框架接入方式,以及一套可直接照做的调试检查清单。读完即可为项目接入"像素级还原真实布局"的骨架屏,无需手写任何描述符。

一、架构总览:从真实 DOM 到骨架矩形

boneyard-js的核心思想是快照真实渲染后的 UI,将其转换为绝对定位的矩形占位元素。所有核心源码位于 packages/boneyard/:

文件职责
src/react.tsxReact 的<Skeleton>组件,同时导出configureBoneyard、registerBones、BoneSuspense
src/preact.tsxPreact 原生集成(无需 compat 层)
src/Skeleton.svelteSvelte 5 组件
src/Skeleton.vueVue 组件
src/angular.tsAngular 组件
src/native.tsx、src/react-native.tsxReact Native 支持
src/extract.tssnapshotBones()DOM 遍历器、fromElement()描述符提取器
src/shared.tsbones 注册表、动画常量(SHIMMER/PULSE/DEFAULTS)、resolveResponsive
src/types.tsSnapshotConfig、Bone、CompactBone、ResponsiveBones等类型定义
src/runtime.ts非 React 场景的 vanillarenderBones()
src/layout.ts描述符驱动的compileDescriptor/computeLayout布局引擎
bin/cli.jsCLI 入口(boneyard-js build)

多框架导出入口

根据 packages/boneyard/package.json 的 exports 字段,包提供多种子路径,全部共享同一套 bones 数据与动画常量:

  • boneyard-js— 导出snapshotBones、renderBones、fromElement、computeLayout等核心 API(见 src/index.ts)
  • boneyard-js/react—Skeleton、registerBones、configureBoneyard
  • boneyard-js/preact—Skeleton、registerBones、configureBoneyard
  • boneyard-js/native—Skeleton、registerBones、configureBoneyard(React Native)
  • boneyard-js/svelte—Skeleton组件、registerBones
  • boneyard-js/vue—Skeleton组件、registerBones、configureBoneyard
  • boneyard-js/angular—SkeletonComponent、registerBones、configureBoneyard
  • boneyard-js/vite—boneyardPlugin()Vite 插件

二、Bones 数据格式与解析优先级

2.1 紧凑数组格式

snapshotBones()产出(或 CLI 写入*.bones.json的)是紧凑数组:

[x%, y_px, w%, h_px, borderRadius, isContainer?]
  • x和w是相对于容器宽度的百分比;
  • y和h是像素值;
  • borderRadius可以是数字(px)或字符串(如"50%");
  • 第 6 个可选元素isContainer(真值)标记容器骨骼——它在渲染时会被跳过。容器骨骼代表父级背景,若与子骨骼同时渲染会产生透明度叠加。

在 src/types.ts 中,CompactBone被定义为 5 元或 6 元元组,normalizeBone()负责把紧凑元组校验(长度必须为 5 或 6)并归一化为结构化Bone对象;同时兼容resolveJsonModule下从 JSON 导入时被收窄为数组的类型情况。仓库示例 packages/boneyard/src/bones/sidebar-nav.bones.json 展示了结构化形式:每个断点下包含name、viewportWidth、width、height与bones数组,例如{ "x": 8, "y": 9, "w": 28, "h": 28, "r": "50%" }即一个圆形头像骨骼。

2.2 骨骼解析优先级

<Skeleton>在运行时按以下优先级获取骨骼数据(React 实现见 src/react.tsx 的initialBones ?? getRegisteredBones(name)):

  1. 显式传入的initialBonesprop(优先级最高);
  2. 按name在注册表中查找(来自registry.js,由registerBones注入,底层是 src/shared.ts 的Map<string, RegisteredBones>);
  3. Fixture 兜底——仅在 CLI 构建模式(window.__BONEYARD_BUILD === true)下生效。

2.3 响应式断点选择

多断点 bones 由ResponsiveBones({ breakpoints: Record<number, SkeletonResult> })表示。resolveResponsive()(见 src/shared.ts)实现"就近匹配":把所有断点键升序排序后,从大到小找到第一个width >= bp的断点;若没有命中则回退到最小断点。<Skeleton>默认用容器实测宽度(container-query 式行为)来选择断点,也可通过select: 'viewport'改用window.innerWidth——这与 CLI 按视口宽度建档的方式一致,适合应用壳布局(容器窄于窗口)的场景。

三、动画常量与暗色模式

3.1 动画常量(单一事实来源)

所有框架实现都从 src/shared.ts 导入动画常量,保证跨框架行为一致:

SHIMMER = { angle: 110, start: 30, end: 70, speed: '2s', lightHighlight: '#f7f7f7', darkHighlight: '#2c2c2c' } PULSE = { speed: '1.8s', lightAdjust: 0.3, darkAdjust: 0.02 } DEFAULTS = { web: { light: '#f0f0f0', dark: '#222222' }, native: { light: '#f0f0f0', dark: '#222222' } }
  • SHIMMER:扫光动画的角度(110°)、渐变的起止位置(30%→70%)、时长(2s)及明暗两套高光色;
  • PULSE:呼吸动画时长 1.8s,lightAdjust/darkAdjust是adjustColor()在明暗模式下对基色做"提亮"的系数(源码中adjustColor(color, amount)同时支持rgba()与#hex两种颜色输入,见 src/shared.ts);
  • CONTAINER:容器骨骼专用的调色系数(adjustment: 0.12/darkAdjustment: 0.03)。

adjustColor是动画实现的关键底层函数:pulse 动画在0%/100%用基色、50%用adjustColor(基色, 0.3)生成高亮帧(React 中以@keyframes bp-${uid}内联样式注入,见 src/react.tsx)。

3.2 暗色模式检测

暗色模式通过<html>或任意祖先元素上的.dark类检测(Tailwind 标准约定),不使用prefers-color-scheme,把控制权明确交给应用开发者。当.dark存在时启用darkColor与darkShimmerColor。React 实现用MutationObserver监听<html>的 class 变化、并监听matchMedia('(prefers-color-scheme: dark)')事件(用于 OS 主题切换触发祖先.dark变化的场景),见 src/react.tsx。

四、SnapshotConfig:控制骨骼提取的四个开关

snapshotConfig以 prop 形式传给<Skeleton>,或作为snapshotBones()的第三个参数,类型定义见 src/types.ts:

{ leafTags?: string[] // 视为原子骨骼的标签(与默认值合并:p,h1-h6,li,td,th) captureRoundedBorders?: boolean // 捕获带边框+圆角但无背景的元素(默认: true) excludeTags?: string[] // 完全跳过这些标签 excludeSelectors?: string[] // 跳过匹配 CSS 选择器的元素 }
  • leafTags:与默认集合合并而非替换。默认集合在 src/extract.ts 定义为p, h1-h6, li, td, th。命中 leafTags 的节点被当作单块扁平骨骼,不再递归其子节点;
  • captureRoundedBorders:默认true。在 src/extract.ts 中,容器只要满足"背景色非透明 / 有背景图 / 有可见边框且圆角"之一即判定为有视觉表面(hasVisualSurface),从而产出容器骨骼。这正是"白色卡片(bg-white rounded-xl border)也能被捕获"的原理——每个背景色都算数,白卡也是卡;
  • excludeTags/excludeSelectors:命中的元素连同所有后代一起跳过(src/extract.ts 中直接return不递归)。excludeSelectors支持任意合法 CSS 选择器:类、ID、属性、标签及组合选择器(如'.card .badge')。

底层snapshotBones()的遍历逻辑(src/extract.ts)值得一提:

  • 读取每个可见元素的getComputedStyle,跳过display:none、visibility:hidden、opacity:0;
  • 图片/表单元素(img/svg/video/canvas/input/button/textarea/select)一律视为叶子;
  • 叶子骨骼取getBoundingClientRect()的精确像素位置,x/w换算为相对根元素的百分比,y/h保持像素;
  • 近正方形的媒体元素(宽高差 < 4px)自动得到50%圆角(适配 SVG 图标、圆形头像);
  • 表格节点(tr/td/th/thead/tbody/table)强制r: 0,避免与overflow:hidden父级冲突。

五、配置文件:boneyard.config.json 全参数详解

boneyard.config.json是首要定制点,同时控制 CLI 构建与运行时默认值。运行时选项会通过configureBoneyard()烘焙进生成的registry.js。完整示例:

{ "breakpoints": [375, 768, 1280], "out": "./src/bones", "wait": 800, "color": "#e5e5e5", "darkColor": "#2a2a2a", "animate": "shimmer", "shimmerColor": "#ebebeb", "darkShimmerColor": "#333333", "speed": "2s", "shimmerAngle": 110, "stagger": false, "transition": false, "boneClass": "", "resolveEnvVars": true, "auth": { "cookies": [{ "name": "session", "value": "env[SESSION_TOKEN]", "domain": "localhost" }], "headers": { "Authorization": "Bearer env[API_TOKEN]" } } }

5.1 构建期选项

Key默认值说明
breakpoints[375, 768, 1280]CLI 捕获的视口宽度(可自动探测 Tailwind 断点)
out./src/bones输出目录
wait800页面加载后等待的毫秒数,再开始捕获

5.2 运行时选项(烘焙进 registry.js)

Key默认值说明
color#f0f0f0骨骼填充色(亮色模式)
darkColor#222222骨骼填充色(暗色模式,.dark类)
animate"pulse"动画:"pulse"、"shimmer"或"solid"
shimmerColor#f7f7f7Shimmer 高光色(亮色模式)
darkShimmerColor#2c2c2cShimmer 高光色(暗色模式)
speed"2s"(shimmer)/ "1.8s"(pulse)动画时长
shimmerAngle110Shimmer 渐变角度(度)
staggerfalse骨骼间动画延迟毫秒数(true = 80ms)
transitionfalse加载结束时的淡出过渡毫秒数(true = 300ms)
boneClass—应用到每个骨骼元素的 CSS 类

5.3 认证与会话支持

auth配置让 CLI/Vite 插件能携带 Cookie 与请求头访问登录态页面,支持env[VAR_NAME]占位符(配合resolveEnvVars: true从.env与process.env解析,缺失时警告并解析为空串,避免静默发送坏 token)。Vite 插件的实现细节见 src/vite.ts:Cookie 会通过白名单ALLOWED_COOKIE_KEYS过滤,请求头会拦截host、content-length等危险头。此外插件还支持cdp选项直连已有 Chrome 调试端口,复用用户浏览器里的真实登录态(src/vite.ts)。

5.4 优先级

组件级 props > 配置文件(经configureBoneyard())> src/shared.ts 包默认值。CLI 标志(flags)对构建期选项会覆盖配置文件。React 端configureBoneyard({...})会把配置合并进全局globalConfig(见 src/react.tsx),组件 props 再覆盖之。

六、实战任务:接入、Fixture、排除与 CLI

6.1 给组件添加骨架屏

import { Skeleton } from 'boneyard-js/react' <Skeleton name="my-component" loading={isLoading}> <MyComponent data={data} /> </Skeleton>

运行时loading={true}时展示骨骼层,loading={false}时展示真实 children;骨骼层以绝对定位覆盖层渲染,并通过aria-busy与data-boneyard-*属性保持可访问性与可调试性(见 src/react.tsx)。

6.2 使用 Fixture(构建期无真实数据时)

<Skeleton name="my-component" loading={isLoading} fixture={<MyFixture />} snapshotConfig={{ leafTags: ["section"] }} > <MyComponent data={data} /> </Skeleton>

关键模式:在 fixture 中用<section>(或任意自定义标签)作为叶子元素,再把该标签加入leafTags,提取器就会把每个 section 当作单块扁平骨骼处理,不再递归其子元素。fixture只在 CLI 设置window.__BONEYARD_BUILD = true时渲染(src/react.tsx 的构建模式分支:fixture ?? children)。

6.3 排除不需要捕获的元素

方式一:标记属性

<nav><Skeleton snapshotConfig={{ excludeSelectors: ['.icon', 'svg'], excludeTags: ['nav'] }}>

6.4 CLI 命令速查

# 自动探测开发服务器 npx boneyard-js build # 显式 URL + 输出目录 npx boneyard-js build http://localhost:PORT --out src/bones # 强制全量重建(跳过 hash 检查) npx boneyard-js build --force # Watch 模式(HMR 时重新捕获) npx boneyard-js build --watch # 自定义断点 npx boneyard-js build --breakpoints 375,640,768,1024,1280,1536 # React Native 模式 npx boneyard-js build --native --out ./bones

6.5 Vite 插件(免第二个终端)

若项目使用 Vite,可直接接入boneyardPlugin()(src/vite.ts):dev server 启动即执行首次捕获,之后每次 HMR 变更在 1.5s 防抖后自动重新捕获,并生成/合并.bones.json与registry.*。插件支持out、breakpoints、wait、routes、skipInitial、cdp、debug等选项,且配置文件的优先级低于插件显式选项。其底层逻辑与 CLI 一致:注入__BONEYARD_BUILD = true、遍历[data-boneyard]标记、按data-boneyard-config读取 snapshotConfig、调用window.__BONEYARD_SNAPSHOT(即snapshotBones)完成捕获。

七、Skeleton Props 完整参考

Prop类型默认值说明
loadingboolean必填显示骨架还是 children
childrenReactNode必填真实内容
namestring必填注册表 key + CLI 标识
initialBonesResponsiveBones—预生成骨骼(覆盖注册表)
colorstring#f0f0f0骨骼填充色(亮色模式),任意 CSS 颜色(hex、rgba、hsl 等)
darkColorstring#222222暗色模式骨骼填充色(.dark类),任意 CSS 颜色
animateAnimationStyle'pulse'"pulse"、"shimmer"、"solid"(也接受 boolean,true=pulse、false=solid)
staggernumber \| booleanfalse交错延迟(true=80ms)
transitionnumber \| booleanfalse淡出时长(true=300ms)
boneClassstring—每个骨骼的 CSS 类
classNamestring—容器类
fallbackReactNode—loading 且无骨骼时显示
fixtureReactNode—供 CLI 捕获的 mock 内容
snapshotConfigSnapshotConfig—控制骨骼提取
select'container' \| 'viewport''container'断点选择的宽度基准

React 还额外提供BoneSuspense(src/react.tsx):与 React 的<Suspense>模型配合,对使用useSuspenseQuery或React.lazy的组件,在挂起时自动展示<Skeleton loading>;构建模式下会把 children 包进<Suspense>,避免挂起查询导致提取崩溃,--wait窗口内查询自然 resolve 后快照真实 DOM。

八、调试检查清单

  1. 骨架屏完全不显示:检查应用入口是否导入了registry.js,且存在对应name的 bones JSON;
  2. 骨骼过多 / 出现内部形状:在snapshotConfig中添加leafTags后重建;
  3. 骨骼与布局不匹配:用--force从当前 DOM 重新生成;
  4. 断点选错:检查容器宽度——骨骼使用就近的<=断点匹配;
  5. 暗色模式未生效:boneyard 依赖<html>或祖先上的.dark类,不使用prefers-color-scheme;
  6. CLI 找不到骨架:组件需要loading={false}(或有 fixture)让真实 UI 渲染出来供捕获;
  7. 透明度叠加 / 双重渲染:容器骨骼(c: true)应在渲染时被跳过——如果出现叠加,说明过滤逻辑缺失(各框架实现均通过normalizeBone(raw).c过滤,见 src/react.tsx 与 src/runtime.ts);
  8. Shimmer 不可见:检查shimmerColor与color的对比度——默认是#f0f0f0上的#f7f7f7。

九、延伸:无 DOM 环境的描述符方案

除浏览器快照路径外,包还提供描述符驱动的布局引擎(src/layout.ts)与 vanilla 运行时renderBones()(src/runtime.ts):fromElement()把渲染后的 DOM 提取为SkeletonDescriptor(含 display/flex/gap/padding/aspectRatio/font/text 等结构化字段),compileDescriptor+computeLayout用编译缓存与文本测量在任意容器宽度下计算骨骼位置,渲染期无需 DOM,适用于 SSR、Worker、边缘函数等场景;skeleton(el)是"提取→计算→渲染"的一站式便捷函数(src/index.ts)。这两条路径与浏览器快照路径共享同一套 bones 格式与动画常量,是理解 boneyard 完整能力边界的补充。

十、最小落地三步走

  1. 构建:npx boneyard-js build(或接入boneyardPlugin()),按需在boneyard.config.json中调整断点、动画、认证;
  2. 接线:在应用入口导入生成的registry.js(自动调用registerBones注册所有 bones JSON);
  3. 包裹:<Skeleton name="my-component" loading={isLoading}>按 name 自动解析骨骼,必要时用initialBones、fixture、snapshotConfig精确控制提取行为。

整个过程无需手写布局描述,boneyard 直接读取浏览器已计算好的像素位置,天然做到"像素级还原真实 UI",这也是其零布局偏移(zero-layout-shift)能力的基础。

【免费下载链接】boneyard

Auto generated skeleton loading framework

项目地址:https://gitcode.com/gh_mirrors/bo/boneyard
点击查看免费下载
上一篇:Voyager 全平台安装指南:商店一键安装、手动抢鲜包与 Safari 原生扩展部署详解
下一篇:FoundationDB 本地开发环境搭建指南:从 macOS 安装、状态验证到首个事务应用

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/9 7:44:36

【ArkUI 练中学】第18课:性能优化进阶与工程化治理

本节目标深入掌握 DevEco Profiler 的场景化分析模板&#xff0c;能够根据问题类型精准选用 Launch、ArkUI、Frame、Time、Allocation、Snapshot、CPU 等模板掌握深度录制与 Trace 分析能力&#xff0c;能够读懂时间线中的渲染流水线、线程调度与跨语言调用栈掌握 Test K…

作者头像 李华
网站建设 2026/10/9 7:44:02

达梦数据库-优化-03-PRJT2操作符优化

目录 一、环境信息 二、介绍 三、优化工具 四、优化过程 1、原始SQL 2、原始SQL预估执行计划 3、原始SQL真实执行计划 4、原始SQL操作符耗时排名 5、参数介绍 6、改写SQL 7、改写SQL预估执行计划 8、改写SQL真实执行计划 9、改写SQL操作符耗时排名 一、环境信息 名…

作者头像 李华
网站建设 2026/10/9 7:42:04

ESP32选型避坑指南:从SoC到模组到料号的三层拆解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/9 7:42:01

从硬件选型到开源发布:空心杯飞控完整设计与调参指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/9 7:41:39

面向跨境带货的多模型融合 AI 视频系统架构拆解

技术流程&#xff1a; 用户输入层&#xff1a;商品白底图、参考爆款视频、脚本文本、输出规格参数 调度中间层&#xff1a;多模型路由调度模块&#xff0c;根据任务类型分发任务至豆包 / 阿里 / 可灵等第三方模型&#xff0c;做输入预处理、输出校验过滤 电商约束层&#xff1a…

作者头像 李华