项目:html5-dataviz | 版本:v1.2 | 生成日期:2026-10-06 | 依据:源码分析
本章是"可复制的数据契约样册":把新增一个案例(或大屏)时需要照抄的全部注册形态——manifest 清单条目、ChartExampleLocalMeta 全字段、各 loaderKind 的 JSON 条目、三种 EChartDemo 执行模式的 SFC 模板、antv/three/webgl 的自驱与壳组件模板、大屏组件映射配置——逐一给出从源码摘录的真实示例。与既有篇目的分工:《03-接口设计》讲契约的字段语义与测试锁定关系,《04-数据模型》讲 schema 的来龙去脉,《06-部署运行》第 5 节讲 SOP 步骤顺序;本章不重复论证,只提供"照着抄就能对"的样例集,每节开头用一行指明出处文件。所有示例均为源码快照摘录(2026-10-06),数字口径含 00-15 篇定稿后新增的 webgl 库(325 条)。
定义于 src/chart-examples/manifest.ts 头部(echarts/antv 清单同文件、three 侧 src/chart-examples/three-manifest.ts、webgl 侧 src/chart-examples/webgl-manifest.ts),完整类型声明如下:
export interface ChartExampleLocalMeta {
id: string
title: string
category: string
tags: string[]
/** three 库专用:资产根路径注入(ASSET_HOST/FILE_HOST/HOST),详情页挂载时透传给示例组件 */
globals?: Record<string, string>
}四个库的真实条目各取一例,覆盖"最小形态"与"带 globals 形态":
// echarts(manifest.ts):最小形态——四必填字段
{
id: 'area-simple',
title: '大数据量面积图',
category: '折线图',
tags: ['折线图', '数据缩放', '提示框', '工具箱', '图形组件'],
},
// three(three-manifest.ts):携带资产根 globals,ASSET_HOST 指向 public/ 下资产目录
{
id: 'webxr_xr_haptics',
title: 'three.js xr - haptics',
category: 'WebXR',
tags: ['Three.js', 'Three.js', '轨道控制', '空间音频(WebAudio)', 'WebXR沉浸', '实时阴影'],
globals: { ASSET_HOST: '/threejs-official/' },
},
// three 的另一变体:双资产根(HOST 与 FILE_HOST 各指一个目录)
{
id: '2025Year',
title: '2025',
category: 'application',
tags: ['Three.js', 'Three.js+Cesium', '后处理管线', '着色器后处理', 'WebGPU后处理', '线条/线框'],
globals: { HOST: '/external-examples/three-cesium-examples/', FILE_HOST: '/external-examples/3d-file-server/' },
},
// webgl(webgl-manifest.ts):中文 id 先例(gen-webgl-registry.mjs 生成,保留源目录命名)
{
id: '1-刷底色',
title: '刷底色',
category: 'webgl',
tags: ['WebGL'],
},四例合读可得三条书写规则。其一,id 是贯穿身份:等于 SFC 文件名({id}.vue)、JSON 条目 id、缩略图文件名三者的公约数,跨库唯一(gen 脚本第 4 步校验);新案例一律建议 kebab-case 英文(webgl 的中文 id 是迁移源既成事实,fs 不解码 URL 编码名的坑见《09-测试与质量保障》第 3 节)。其二,tags 首位是库标识习惯(three 条目带 'Three.js'、antv 条目带 'antv'/'g2plot'、webgl 带 'WebGL'),参与搜索域。其三,globals 注释写明"three 库专用",但类型上不限制库——它是详情页向组件注入资产根路径的唯一通道,新增资产根约定时应同步 three-data.test.ts / webgl-data.test.ts 的逐字段对齐断言。清单统一出口为 LOCAL_LIBRARY_MANIFESTS(manifest.ts 尾部,Record 结构,键为四库 id);echarts/antv 两份清单的生成器不在仓库内(手工维护 + git 留痕),three/webgl 两份由 scripts/gen-three-registry.mjs / gen-webgl-registry.mjs 生成、禁止手改。
两种维护方式并存的局面值得展开一句:同样是"生成物",three/webgl 清单与 echarts/antv 清单的可信度并不对等——前者的生成器在仓库内、重跑即重建,后者的生成器已失联、任何修改都是"手改生成物"。因此本章样例在两个库系中的用法也不同:照抄 echarts/antv 条目时,请同时复刻它的字段形态与排序习惯(manifest 按 id 字母序插入、JSON 条目字段按 schema 顺序),并在提交信息中写明涉及 id(git 留痕是未来找回生成器后 diff 对账的唯一依据);照抄 three/webgl 条目时则不应手改清单文件,批量场景一律走 gen 脚本,单条手工新增(无上游源时)虽属允许,但完成后应立即跑 three-data.test.ts / webgl-data.test.ts 确认三处(JSON、manifest、缩略图)对齐。这套差别对待不是双标,而是《13-技术债务与演进建议》第 1 条登记的风险在操作层的投影:生成器缺失的库,其清单一致性只能靠人的纪律兜底。
定义于 src/types/chart-examples.ts,数据集为 src/data/charts/{echarts,antv,three,webgl}.json。19 字段的语义表见《04-数据模型》第 1 节,本节给每种 loaderKind 一条完整真实条目(为节省篇幅省略 createAt/updatedAt 之外无省略字段;代码字段的完整内容见数据集本体)。
// ① echarts / loaderKind: "option"(echarts.json 的 area-basic 条目)
{
"id": "area-basic",
"library": "echarts",
"title": "基础面积图",
"titleEn": "Basic area chart",
"description": "Basic area chart - 难度 1",
"category": "折线图",
"loaderKind": "option",
"tags": ["折线图"],
"difficulty": "beginner",
"sourceUrl": "https://echarts.apache.org/examples/zh/editor.html?c=area-basic",
"sortOrder": 6,
"status": "published",
"requiresGl": false,
"requiresMap": false,
"thumbnail": "/echarts-thumbs/area-basic.webp",
"createdAt": "2026-06-21T21:01:49.329Z",
"updatedAt": "2026-06-23T15:17:38.736Z"
}
// area-simple 等 294 条已 SFC 化的条目在 JSON 里没有代码字段(slim 脚本删除);
// 仅 54 条兜底 echarts 条目保留 optionCode(多语句官方脚本,结尾留 option 或自行 setOption)。
// ② echarts / loaderKind: "api-async"(echarts.json 的 archive-custom-aggregate-scatter-bar 条目,兜底形态)
// 本条是"迁移遗留双格式"活样本:optionCode(官方多语句脚本)+ componentCode + initCode 三字段并存,
// 渲染走 optionCode 求值链(usesSfc 类型优先路由豁免,见《18-代码走读实录》2.1 节)。
{
"id": "archive-custom-aggregate-scatter-bar",
"library": "echarts",
"title": "聚合分割形变(散点图 - 柱状图)",
"titleEn": "Aggregate Morphing Between Scatter and Bar",
"description": "Aggregate Morphing Between Scatter and Bar - 难度 9 - 异步数据",
"category": "自定义系列",
"loaderKind": "api-async",
"tags": ["自定义系列", "提示框", "视觉映射", "动画", "数据集", "异步数据"],
"difficulty": "advanced",
"sourceUrl": "https://echarts.apache.org/examples/zh/editor.html?c=archive-custom-aggregate-scatter-bar",
"sortOrder": 0,
"status": "published",
"requiresGl": false,
"requiresMap": false,
"thumbnail": "/echarts-thumbs/archive-custom-aggregate-scatter-bar.webp",
"createdAt": "2026-06-21T21:01:49.319Z",
"updatedAt": "2026-06-23T15:17:38.692Z",
"optionCode": "var SCATTER_COLORS = ['#5470c6', ...数十行声明与 echarts.init / myChart.setOption(option) 逻辑(原样收录官方脚本)",
"componentCode": "<template>...(迁移早期生成的完整 SFC 字符串,当前链路不消费)",
"initCode": "…(option 回填后的五形参补充脚本,少见)"
}
// ③ antv / loaderKind: "antv-config"(antv.json 的 antv-area-basic-basic-annotation 条目,兜底形态带 optionCode)
{
"id": "antv-area-basic-basic-annotation",
"library": "antv",
"title": "area basic basic-annotation",
"titleEn": "area basic basic-annotation",
"description": "area basic basic-annotation 示例(来自 AntV G2Plot 官方文档)",
"category": "面积图",
"loaderKind": "antv-config",
"tags": ["antv", "g2plot", "面积图"],
"difficulty": "intermediate",
"sourceUrl": "https://github.com/antvis/g2plot/tree/master/site/examples/area/basic/demo",
"sortOrder": 1,
"status": "published",
"requiresGl": false,
"requiresMap": false,
"thumbnail": "/chart-thumbs/antv-area-basic-basic-annotation.webp",
"createdAt": "2026-06-23T11:25:50.951Z",
"updatedAt": "2026-06-23T16:09:05.797Z",
"optionCode": "const data = []; const categories = [...]; ...; return { plotClass: 'Area', options: { data, xField: 'year', yField: 'value', seriesField: 'category', ... } }"
}
// ④ three / loaderKind: "local"(three.json 的 machineRoom 条目——全量本地 SFC 库的标准形态,无代码字段)
{
"id": "machineRoom",
"library": "three",
"title": "机房展示",
"titleEn": null,
"description": "这是一个基于 Three.js 的机房示例。运用了 GLTF模型加载、纹理加载、射线拾取交互 技术。",
"category": "机房",
"loaderKind": "local",
"tags": ["Three.js", "机房", "GLTF模型加载", "纹理加载", "射线拾取交互"],
"difficulty": null,
"sourceUrl": null,
"sortOrder": 0,
"status": "published",
"requiresGl": false,
"requiresMap": false,
"thumbnail": "/example-thumbs/threejs-lesson/02-machineroom/machineRoom.jpg",
"createdAt": "2026-10-06T00:57:05.771Z",
"updatedAt": "2026-10-06T00:57:05.771Z"
}
// ⑤ webgl / loaderKind: "local"(webgl.json 的 1-刷底色 条目——第四库与 three 同构)
{
"id": "1-刷底色",
"library": "webgl",
"title": "刷底色",
"titleEn": null,
"description": "基于原生 WebGL 的「刷底色」教学示例,演示对应章节的渲染流程。",
"category": "webgl",
"loaderKind": "local",
"tags": ["WebGL"],
"difficulty": null,
"sourceUrl": null,
"sortOrder": 0,
"status": "published",
"requiresGl": false,
"requiresMap": false,
"thumbnail": "/example-thumbs/webgl/kaikeba-webgl/01-webgl-入门-webgl/1-刷底色.webp",
"createdAt": "2026-10-06T05:03:28.056Z",
"updatedAt": "2026-10-06T05:03:28.056Z"
}样例集背后的守恒规则(被 src/data/charts/__tests__/charts-data.test.ts 机器锁定):有本地 SFC 的条目必无任何代码字段,无本地 SFC 的兜底条目必带至少一个代码字段。因此新增案例时:有 SFC → 不写代码字段;做兜底条目 → 只写一个代码字段且 loaderKind 与之匹配(optionCode 配 option/api-async/antv-config,componentCode 配 component——但 component 类原则上不再新增,理由见《11-扩展开发指南》SOP-F)。JSON 侧另有一个 schema 外字段 __source(仅 three.json,六种迁移源取值,运行时不消费、仅供 gen 脚本按源合并重跑)。
新增条目时除了 JSON 与清单,还有一组由路径约定构成的隐式契约需要同步核对,它们不出现在任何 schema 里,却决定了"数据条目与磁盘资产能否对上"。缩略图:JSON 的 thumbnail 指向 public/ 下的真实文件(echarts 用 /echarts-thumbs/、antv/兜底通用 /chart-thumbs/、three/webgl 用 /example-thumbs/{源}/{章节}/),置 null 时列表页回落 /chart-thumbs/{id}.webp 兜底路径——兜底路径也要求文件真实存在,否则卡片以 📊 占位符静默降级(echarts/antv 侧无测试校验,是上线检查项而非测试项)。图表数据:echarts 官方脚本里的相对取数路径在运行时被拼上 /echarts-data 前缀(EChartDemo.fetchJson 一律拼、Renderer 相对路径拼、沙箱注入 ROOT_PATH 变量,三处语义一致),因此收录官方示例时要确认对应数据文件确实在 public/echarts-data/ 下。地图:requiresMap: true 的条目由宿主预注册 china/world 两张(/map-geojson/),第三张地图须示例内 ctx.registerMap 自注册。three/webgl:资产根完全由 manifest 的 globals 决定,资产文件在 public/{ASSET_HOST 指向目录}/ 下,路径拼写错一个字符的表现是运行时 404 而非任何构建期报错——这也是 gen 脚本第 4 步"缩略图存在性校验、失败退出码 1"存在的理由:把"路径对不上"提前到生成期暴露。
echarts 本地 SFC 的契约容器是 src/chart-examples/EChartDemo.vue(props/ChartContext 全表见《15-接口全量参考》第 4 节),三种执行模式的真实模板如下。选型判据先行总结:能用 option 模式就不要用钩子——option 是三者中唯一"声明式"的形态,容器能替它处理一切时序;onReady 用于"初始化需要异步数据或注册类 API"的场景;setup 用于"存在实例级副作用(定时器/事件监听)"的场景,它以返回清理函数为代价换取最强的控制力。三种模式可两两组合但语义有互斥细节(静态 option 与钩子互斥、onReady 先于 setup),逐条见各小节末尾。另需说明:以下三个源文件的脚本均为官方示例脚本的迁移改写产物(生成器统一注入"等待 v-chart 子组件挂载完成"的注释),阅读时把注释当作生成器签名而非代码逻辑。
src/chart-examples/echarts/line/line-simple.vue)<template>
<div class="demo-container">
<EChartDemo :option="option" />
</div>
</template>
<script setup>
import EChartDemo from '../../EChartDemo.vue'
// 等待 v-chart 子组件挂载完成,确保 chartRef 可用
const option = {
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
},
yAxis: {
type: 'value',
},
series: [
{
data: [150, 230, 224, 218, 135, 147, 260],
type: 'line',
},
],
}
</script>
<style scoped>
.demo-container {
position: relative;
width: 100%;
height: 100%;
min-height: 280px;
border-radius: inherit;
overflow: hidden;
}
</style>这是 294 个 SFC 的最小形态:模板三行、数据一个普通对象、样式一块固定 scoped 块。适用判据:不需要异步取数、不需要 registerMap、不需要定时器或事件监听。option 也支持传 ref(option)(需要响应式整体替换时),normalizeOption 会按 'value' in o 自动解包。注意开头注释"等待 v-chart 子组件挂载完成"是生成器统一注入的提示语,不是代码要求——挂载等待由 EChartDemo 的 waitForInstance 负责(机制见《18-代码走读实录》3.1 节)。
src/chart-examples/echarts/parallel/parallel-nutrients.vue 节选)<template>
<div class="demo-container">
<EChartDemo :on-ready="onReady" />
</div>
</template>
<script setup>
import EChartDemo from '../../EChartDemo.vue'
async function onReady(ctx) {
// 等待 v-chart 子组件挂载完成,确保 chartRef 可用
const indices = { name: 0, group: 1, id: 16 }
const schema = [
{ name: 'name', index: 0 },
{ name: 'group', index: 1 },
// …营养素字段表(源文件完整保留 17 列)
]
const groupCategories = []
const groupColors = []
ctx.fetchJson('/data/asset/data/nutrients.json').then(function (data) {
normalizeData(data)
ctx.setOption(getOption(data))
})
// …normalizeData / getOption 等数据加工函数(源文件原样保留)
}
</script>onReady 的适用判据:初始化依赖异步数据或需要 ctx.echarts 的注册类 API(registerMap/registerTransform)。契约语义:钩子收到的 ctx 是 ChartContext 七件套(echarts/myChart/setOption/registerMap/registerTransform/loadScript/fetchJson),返回非空 option 则由容器代为 setOption(本例选择自行调 ctx.setOption,两种写法等价二选一);ctx.fetchJson 固定拼 /echarts-data 前缀——脚本里的相对路径与 ECharts 官方编辑器完全一致,资产已在 public/echarts-data/ 本地化。需要 GL 系列时在 SFC 顶部补 import 'echarts/gl'(置于 echarts import 之后)。
src/chart-examples/echarts/sankey/sankey-energy.vue)<template>
<div class="demo-container">
<EChartDemo :setup="setup" />
</div>
</template>
<script setup>
import EChartDemo from '../../EChartDemo.vue'
function setup(ctx) {
// 等待 v-chart 子组件挂载完成,确保 chartRef 可用
ctx.myChart.showLoading()
ctx.fetchJson('/data/asset/data/energy.json').then(function (data) {
ctx.myChart.hideLoading()
const option = {
title: { text: 'Sankey Diagram' },
tooltip: { trigger: 'item', triggerOn: 'mousemove' },
series: [
{
type: 'sankey',
data: data.nodes,
links: data.links,
emphasis: { focus: 'adjacency' },
lineStyle: { color: 'gradient', curveness: 0.5 },
},
],
}
ctx.setOption(option)
})
}
</script>setup 的适用判据:需要 setInterval/setTimeout、myChart.on 事件监听、或任何"实例级副作用"。关键契约义务:函数体内创建了定时器/监听时必须返回清理函数(return () => { clearInterval(timer) }),容器在重试与卸载两个时机统一调用——不返回清理函数的定时器类示例会在快速切换时叠加定时器,这是历史事故类别(《07-模块详解》4.2 节)。setup 与 onReady 可共存,执行顺序固定为先 onReady 后 setup;两者任一存在时静态 option 不生效(互斥语义见《12-FAQ与故障排查》第 7 节第一条)。含清理函数的完整示例可参考 src/chart-examples/echarts/graph/graph-force-dynamic.vue。
本节的三个模板分别代表三种"无 EChartDemo 契约"的执行形态:antv 是完全自驱(示例组件自己管实例生命周期)、three 是厚壳托管(壳统一管 renderer 与渲染循环,示例只声明场景内容)、webgl 是薄壳直通(壳只提供 canvas,示例直接操作原生 WebGL 上下文)。三种形态的复杂度依次递减、自由度依次递增,选择权不在示例作者而在库的迁移策略——这是"库级约定优先于示例级偏好"的体现,同一库内的示例必须保持同构,否则生成器、清扫脚本与排查经验都无从复用。
src/chart-examples/antv/line/antv-line-basic.vue)<script setup>
import { ref, onMounted } from 'vue'
import { Line } from '@antv/g2plot'
const containerRef = ref(null)
onMounted(() => {
const data = [
{ month: '一月', value: 120 },
{ month: '二月', value: 200 },
// …共七个月数据
]
const line = new Line(containerRef.value, {
data,
xField: 'month',
yField: 'value',
smooth: true,
color: '#6366f1',
point: { size: 4, shape: 'circle' },
label: {},
})
line.render()
})
</script>
<template>
<div ref="containerRef" class="chart-wrap"></div>
</template>antv 不经过任何宿主组件:onMounted 里 new Plot(container, options) + render(),规范写法应配 onBeforeUnmount(() => plot.destroy())(防实例泄漏,与 EChartDemo 的 cleanupFn 语义对齐)。G2Plot 的类名即 loaderKind 为 antv-config 的兜底条目里 plotClass 字段的合法取值('Line'/'Area'/'Column' 等)。
src/chart-examples/three/threejs-lesson/03-basics/dpr.vue)<template>
<ExampleScene
camera="perspective"
:camera-position="[0, 0, 5]"
:max-pixel-ratio="devicePixelRatio"
@ready="onReady"
/>
</template>
<script setup lang="ts">
import * as THREE from 'three'
import ExampleScene from '../../ExampleScene.vue'
let cubes: any[] = []
function onReady(ctx: any) {
const geometry = new THREE.BoxGeometry()
const material = new THREE.MeshPhongMaterial({ color: 0x44aa88 })
cubes = [-2, 0, 2].map((x) => {
const cube = new THREE.Mesh(geometry, material)
cube.position.x = x
return cube
})
ctx.scene.add(...cubes)
const light = new THREE.DirectionalLight(0xffffff, 1)
light.position.set(-1, 2, 4)
ctx.scene.add(light)
ctx.addUpdateCallback(() => {
cubes.forEach((cube) => {
cube.rotation.x += 0.01
cube.rotation.y += 0.01
})
})
}
</script>ExampleScene(src/chart-examples/three/ExampleScene.vue,含 CSS3D/SVG/WebGPU/WebXR 变体壳)内部由 stage/useExampleStage.ts 统一管理 renderer/controls/渲染循环与 dispose——示例作者只做三件事:声明相机配置、在 onReady(ctx) 里向 ctx.scene 加对象、用 ctx.addUpdateCallback 注册逐帧逻辑。禁令:不要绕过壳自建 WebGLRenderer,context 上限防护(forceContextLoss)在壳里(ADR-007)。
src/chart-examples/webgl/webgl/kaikeba-webgl/01-webgl-入门-webgl/1-刷底色.vue)<template>
<WebGLExampleScene @ready="onReady" />
</template>
<script setup lang="ts">
import WebGLExampleScene from '@webgl-examples/components/WebGLExampleScene.vue'
async function onReady({ canvas, container, addUpdateCallback, resize }: { canvas: HTMLCanvasElement; container: HTMLElement; addUpdateCallback: (fn: () => void) => void; resize: (w: number, h: number) => void }) {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
// 使用canvas 获取webgl 绘图上下文
const gl = canvas.getContext("webgl")!!;
// 指定将要用来清空绘图区的颜色
gl.clearColor(1, 1, 0, 1);
// 使用之前指定的颜色,清空绘图区
gl.clear(gl.COLOR_BUFFER_BIT);
}
</script>webgl 库与 three 同构但壳更薄:WebGLExampleScene 提供 canvas 与就绪回调,示例直接操作原生 WebGL 上下文(教学示例的意义就在于裸写管线);教学代码常需 rAF/事件的全局资源回收,由 @webgl-examples/composables/useGraphicsCleanup 的引用计数 patch 机制统一承接(组件无需 import,场景内部自动接入)。@webgl-examples 别名在 vite.config.ts / tsconfig.json 双处注册,指向 src/chart-examples/webgl。
新增大屏要同步的两张表(对齐关系由 src/config/__tests__/bigscreenComponents.test.ts 双向锁定):
// ① 清单真源:src/config/bigscreenData.ts
export interface BigScreenConfig {
id: string
title: string
description: string
category: string
thumbnail: string
}
export const bigscreenList: BigScreenConfig[] = [
{
id: 'business-dashboard',
title: '业务数据可视化大屏',
description: '外卖业务数据大屏,包含用户统计、地图可视化、实时订单趋势等模块。',
category: '数据仪表盘',
thumbnail: '/bigscreen-thumbnails/business-dashboard.webp',
},
// …共 22 条
]
// ② 组件加载真源:src/config/bigscreenComponents.ts
export const bigscreenComponentMap: Record<
string,
() => Promise<Component | { default: Component }>
> = {
'business-dashboard': () => import('@/views/bigscreen/business/BusinessDashboardPage.vue'),
'report-dashboard': () => import('@/views/bigscreen/report/ReportDashboardPage.vue'),
dashboard: () => import('@/views/bigscreen/dashboard/DashboardPage.vue'),
// …22 个键与 bigscreenList 的 id 一一对应,多写少写都会被测试拦截
}书写要点:两处 id 必须逐字符一致(含连字符与大小写);加载器返回模块命名空间(含 default)与 vue 异步组件约定一致;category 从现有 12 类中选;缩略图放 public/bigscreen-thumbnails/{id}.webp(存在性由 bigscreenThumbnails.test.ts 校验)。大屏组件自身的最小骨架是根节点 DatavContainer(1920×1080 自适应缩放)+ 内部 <v-chart>(全局已注册免 import)+ 暗色主题(src/utils/echarts-theme.ts 的 darkEchartsTheme)——完整页面骨架与父子组件拆分见《02-页面设计》第 7 节的 SalesAnalysisPage 示范。
把本章五个样例集映射到《11-扩展开发指南》的 SOP 场景:SOP-A(新增 echarts/antv 案例)→ 第 3 节三种模式模板 + 第 4.1 节;SOP-E(新增 three 案例)→ 第 4.2 节 + 第 1 节带 globals 条目;SOP-F(新增兜底条目)→ 第 2 节样例 ②③ 的代码字段形态;SOP-B(新增大屏)→ 第 5 节;SOP-C(新增图表库)→ 第 1 节出口结构 + 第 2 节 schema 整体复制。抄完任一样例后的固定收尾四连(typecheck/lint/test/smoke)与需要同步修改的守恒测试数字(FILES 硬编码)见《11-扩展开发指南》第 7 节与《06-部署运行》第 5 节第 5 步——样册解决"写成什么样",SOP 解决"按什么顺序改哪些文件",两者配套使用。
最后强调一次样册与真实数据的校验关系:本章所有示例都摘自仓库真实文件,但它们只是"当前快照"——真正的契约仲裁者永远是守恒测试族(charts-data.test.ts、three-data.test.ts、webgl-data.test.ts)与渲染链测试(EChartDemo/Renderer/VueSfcRenderer 三件套)。抄样例写完条目后,跑一次 pnpm test 比逐字段目检样例可靠得多:字段名笔误、代码字段误填、SFC 与 JSON id 错位,这些测试都能定位到具体条目与字段名(《12-FAQ与故障排查》第 5 节的"测试红了怎么读"是配套的解读手册)。若发现本章样例与测试断言冲突,以测试为准并回改本章——这份样册的价值在于降低首次查阅成本,不在于取代测试成为第二真源。