[{"data":1,"prerenderedAt":2185},["ShallowReactive",2],{"article-/topics/design/design-system-versioning-guide":3,"related-design":703,"content-query-ecapXgBsOi":1639},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":8,"description":9,"date":10,"topic":5,"author":11,"tags":12,"image":18,"featured":6,"readingTime":19,"body":20,"_type":237,"_id":698,"_source":699,"_file":700,"_stem":701,"_extension":702},"/topics/design/design-system-versioning-guide","design",false,"","设计系统版本管理完全指南","系统讲解设计系统的版本管理策略，包括语义化版本、变更日志、兼容性处理、发布流程等核心内容，帮助团队高效管理组件库迭代。","2024-12-31","HTMLPAGE 团队",[13,14,15,16,17],"版本管理","设计系统","语义化版本","组件库","变更日志","/images/topics/design/design-system-versioning-guide.jpg","18分钟",{"type":21,"children":22,"toc":660},"root",[23,31,37,83,88,95,109,196,201,210,215,223,228,234,245,250,255,266,277,282,287,298,303,312,322,331,337,355,366,374,379,384,395,400,409,414,419,500,505,513,518,527,532,538,549,554,563,568,573,582,588,593,598,607,612,617,625,634,652],{"type":24,"tag":25,"props":26,"children":28},"element","h2",{"id":27},"版本管理的重要性",[29],{"type":30,"value":27},"text",{"type":24,"tag":32,"props":33,"children":34},"p",{},[35],{"type":30,"value":36},"设计系统作为多项目共享的基础设施，版本管理尤为关键：",{"type":24,"tag":38,"props":39,"children":40},"ul",{},[41,53,63,73],{"type":24,"tag":42,"props":43,"children":44},"li",{},[45,51],{"type":24,"tag":46,"props":47,"children":48},"strong",{},[49],{"type":30,"value":50},"稳定性",{"type":30,"value":52}," - 业务项目可以锁定可靠版本",{"type":24,"tag":42,"props":54,"children":55},{},[56,61],{"type":24,"tag":46,"props":57,"children":58},{},[59],{"type":30,"value":60},"可追溯",{"type":30,"value":62}," - 了解每个版本的变化",{"type":24,"tag":42,"props":64,"children":65},{},[66,71],{"type":24,"tag":46,"props":67,"children":68},{},[69],{"type":30,"value":70},"渐进升级",{"type":30,"value":72}," - 控制升级节奏和风险",{"type":24,"tag":42,"props":74,"children":75},{},[76,81],{"type":24,"tag":46,"props":77,"children":78},{},[79],{"type":30,"value":80},"协作效率",{"type":30,"value":82}," - 团队共识和沟通基础",{"type":24,"tag":25,"props":84,"children":86},{"id":85},"语义化版本规范",[87],{"type":30,"value":85},{"type":24,"tag":89,"props":90,"children":92},"h3",{"id":91},"semver-基础",[93],{"type":30,"value":94},"SemVer 基础",{"type":24,"tag":32,"props":96,"children":97},{},[98,100,107],{"type":30,"value":99},"遵循 ",{"type":24,"tag":101,"props":102,"children":104},"code",{"className":103},[],[105],{"type":30,"value":106},"MAJOR.MINOR.PATCH",{"type":30,"value":108}," 格式：",{"type":24,"tag":110,"props":111,"children":112},"table",{},[113,137],{"type":24,"tag":114,"props":115,"children":116},"thead",{},[117],{"type":24,"tag":118,"props":119,"children":120},"tr",{},[121,127,132],{"type":24,"tag":122,"props":123,"children":124},"th",{},[125],{"type":30,"value":126},"版本号",{"type":24,"tag":122,"props":128,"children":129},{},[130],{"type":30,"value":131},"含义",{"type":24,"tag":122,"props":133,"children":134},{},[135],{"type":30,"value":136},"示例场景",{"type":24,"tag":138,"props":139,"children":140},"tbody",{},[141,160,178],{"type":24,"tag":118,"props":142,"children":143},{},[144,150,155],{"type":24,"tag":145,"props":146,"children":147},"td",{},[148],{"type":30,"value":149},"MAJOR",{"type":24,"tag":145,"props":151,"children":152},{},[153],{"type":30,"value":154},"不兼容的 API 变更",{"type":24,"tag":145,"props":156,"children":157},{},[158],{"type":30,"value":159},"删除组件、修改 Props 类型",{"type":24,"tag":118,"props":161,"children":162},{},[163,168,173],{"type":24,"tag":145,"props":164,"children":165},{},[166],{"type":30,"value":167},"MINOR",{"type":24,"tag":145,"props":169,"children":170},{},[171],{"type":30,"value":172},"向后兼容的新功能",{"type":24,"tag":145,"props":174,"children":175},{},[176],{"type":30,"value":177},"新增组件、新增可选 Props",{"type":24,"tag":118,"props":179,"children":180},{},[181,186,191],{"type":24,"tag":145,"props":182,"children":183},{},[184],{"type":30,"value":185},"PATCH",{"type":24,"tag":145,"props":187,"children":188},{},[189],{"type":30,"value":190},"向后兼容的问题修复",{"type":24,"tag":145,"props":192,"children":193},{},[194],{"type":30,"value":195},"Bug 修复、性能优化",{"type":24,"tag":89,"props":197,"children":199},{"id":198},"预发布版本",[200],{"type":30,"value":198},{"type":24,"tag":202,"props":203,"children":205},"pre",{"code":204},"1.0.0-alpha.1   # 内部测试\n1.0.0-beta.1    # 公开测试\n1.0.0-rc.1      # 发布候选\n1.0.0           # 正式发布\n",[206],{"type":24,"tag":101,"props":207,"children":208},{"__ignoreMap":7},[209],{"type":30,"value":204},{"type":24,"tag":89,"props":211,"children":213},{"id":212},"版本号决策",[214],{"type":30,"value":212},{"type":24,"tag":202,"props":216,"children":218},{"code":217},"是否删除了组件或属性？\n├── 是 → MAJOR\n└── 否 → 是否修改了必填属性或类型？\n         ├── 是 → MAJOR\n         └── 否 → 是否新增了组件或功能？\n                  ├── 是 → MINOR\n                  └── 否 → PATCH\n",[219],{"type":24,"tag":101,"props":220,"children":221},{"__ignoreMap":7},[222],{"type":30,"value":217},{"type":24,"tag":25,"props":224,"children":226},{"id":225},"变更日志管理",[227],{"type":30,"value":225},{"type":24,"tag":89,"props":229,"children":231},{"id":230},"changelog-格式",[232],{"type":30,"value":233},"Changelog 格式",{"type":24,"tag":202,"props":235,"children":240},{"code":236,"language":237,"meta":7,"className":238},"# Changelog\n\n## [2.3.0] - 2024-12-31\n\n### Added\n- 新增 `DatePicker` 日期选择器组件\n- `Button` 组件新增 `icon` 插槽\n\n### Changed\n- `Modal` 组件默认动画时长从 300ms 调整为 200ms\n\n### Deprecated\n- `Input` 组件的 `clearable` 属性将在 3.0 移除，请使用 `allowClear`\n\n### Fixed\n- 修复 `Select` 组件在 Safari 下的样式问题 (#123)\n- 修复 `Table` 分页器点击无效的问题 (#145)\n\n## [2.2.1] - 2024-12-20\n\n### Fixed\n- 修复 `Tooltip` 组件定位偏移问题\n","markdown",[239],"language-markdown",[241],{"type":24,"tag":101,"props":242,"children":243},{"__ignoreMap":7},[244],{"type":30,"value":236},{"type":24,"tag":89,"props":246,"children":248},{"id":247},"自动生成变更日志",[249],{"type":30,"value":247},{"type":24,"tag":32,"props":251,"children":252},{},[253],{"type":30,"value":254},"使用 Conventional Commits 规范：",{"type":24,"tag":202,"props":256,"children":261},{"code":257,"language":258,"meta":7,"className":259},"# 提交格式\n\u003Ctype>(\u003Cscope>): \u003Cdescription>\n\n# 示例\nfeat(Button): add icon slot support\nfix(Select): fix Safari styling issue\ndocs(Modal): update API documentation\nBREAKING CHANGE: remove deprecated `clearable` prop\n","bash",[260],"language-bash",[262],{"type":24,"tag":101,"props":263,"children":264},{"__ignoreMap":7},[265],{"type":30,"value":257},{"type":24,"tag":202,"props":267,"children":272},{"code":268,"language":269,"meta":7,"className":270},"// package.json\n{\n  \"scripts\": {\n    \"changelog\": \"conventional-changelog -p angular -i CHANGELOG.md -s\"\n  }\n}\n","javascript",[271],"language-javascript",[273],{"type":24,"tag":101,"props":274,"children":275},{"__ignoreMap":7},[276],{"type":30,"value":268},{"type":24,"tag":25,"props":278,"children":280},{"id":279},"兼容性处理",[281],{"type":30,"value":279},{"type":24,"tag":89,"props":283,"children":285},{"id":284},"废弃流程",[286],{"type":30,"value":284},{"type":24,"tag":202,"props":288,"children":293},{"code":289,"language":290,"meta":7,"className":291},"// 1. 标记废弃\n/**\n * @deprecated 请使用 allowClear 代替，将在 3.0 移除\n */\ninterface InputProps {\n  clearable?: boolean\n  allowClear?: boolean\n}\n\n// 2. 运行时警告\nconst Input = (props) => {\n  if (props.clearable !== undefined) {\n    console.warn(\n      '[DesignSystem] Input: clearable 属性已废弃，' +\n      '请使用 allowClear 代替，将在 3.0 版本移除'\n    )\n  }\n  \n  const shouldClear = props.allowClear ?? props.clearable\n  // ...\n}\n\n// 3. 文档标记\n","typescript",[292],"language-typescript",[294],{"type":24,"tag":101,"props":295,"children":296},{"__ignoreMap":7},[297],{"type":30,"value":289},{"type":24,"tag":89,"props":299,"children":301},{"id":300},"迁移指南",[302],{"type":30,"value":300},{"type":24,"tag":202,"props":304,"children":307},{"code":305,"language":237,"meta":7,"className":306},"# 从 v2 升级到 v3\n\n## 破坏性变更\n\n### Button 组件\n\n**变更**：`type` 属性重命名为 `variant`\n\n```diff\n- \u003CButton type=\"primary\">提交\u003C/Button>\n+ \u003CButton variant=\"primary\">提交\u003C/Button>\n",[239],[308],{"type":24,"tag":101,"props":309,"children":310},{"__ignoreMap":7},[311],{"type":30,"value":305},{"type":24,"tag":32,"props":313,"children":314},{},[315,320],{"type":24,"tag":46,"props":316,"children":317},{},[318],{"type":30,"value":319},"迁移脚本",{"type":30,"value":321},"：",{"type":24,"tag":202,"props":323,"children":326},{"code":324,"language":258,"meta":7,"className":325},"npx @design-system/codemod button-type-to-variant ./src\n",[260],[327],{"type":24,"tag":101,"props":328,"children":329},{"__ignoreMap":7},[330],{"type":30,"value":324},{"type":24,"tag":89,"props":332,"children":334},{"id":333},"input-组件",[335],{"type":30,"value":336},"Input 组件",{"type":24,"tag":32,"props":338,"children":339},{},[340,345,347,353],{"type":24,"tag":46,"props":341,"children":342},{},[343],{"type":30,"value":344},"变更",{"type":30,"value":346},"：移除 ",{"type":24,"tag":101,"props":348,"children":350},{"className":349},[],[351],{"type":30,"value":352},"clearable",{"type":30,"value":354}," 属性",{"type":24,"tag":202,"props":356,"children":361},{"code":357,"language":358,"meta":7,"className":359},"- \u003CInput clearable />\n+ \u003CInput allowClear />\n","diff",[360],"language-diff",[362],{"type":24,"tag":101,"props":363,"children":364},{"__ignoreMap":7},[365],{"type":30,"value":357},{"type":24,"tag":202,"props":367,"children":369},{"code":368},"\n### Codemod 自动迁移\n\n```javascript\n// codemods/button-type-to-variant.js\nmodule.exports = function transformer(file, api) {\n  const j = api.jscodeshift\n  const root = j(file.source)\n  \n  // 找到所有 Button 组件\n  root\n    .find(j.JSXElement, {\n      openingElement: { name: { name: 'Button' } }\n    })\n    .forEach(path => {\n      const attrs = path.node.openingElement.attributes\n      \n      attrs.forEach(attr => {\n        if (attr.name && attr.name.name === 'type') {\n          attr.name.name = 'variant'\n        }\n      })\n    })\n  \n  return root.toSource()\n}\n",[370],{"type":24,"tag":101,"props":371,"children":372},{"__ignoreMap":7},[373],{"type":30,"value":368},{"type":24,"tag":25,"props":375,"children":377},{"id":376},"发布流程",[378],{"type":30,"value":376},{"type":24,"tag":89,"props":380,"children":382},{"id":381},"自动化发布",[383],{"type":30,"value":381},{"type":24,"tag":202,"props":385,"children":390},{"code":386,"language":387,"meta":7,"className":388},"# .github/workflows/release.yml\nname: Release\n\non:\n  push:\n    branches: [main]\n\njobs:\n  release:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n      \n      - uses: actions/setup-node@v4\n        with:\n          node-version: 20\n          registry-url: https://registry.npmjs.org/\n      \n      - run: npm ci\n      - run: npm test\n      - run: npm run build\n      \n      # 自动版本号和发布\n      - name: Release\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}\n        run: npx semantic-release\n","yaml",[389],"language-yaml",[391],{"type":24,"tag":101,"props":392,"children":393},{"__ignoreMap":7},[394],{"type":30,"value":386},{"type":24,"tag":89,"props":396,"children":398},{"id":397},"发布检查清单",[399],{"type":30,"value":397},{"type":24,"tag":202,"props":401,"children":404},{"code":402,"language":237,"meta":7,"className":403},"## 发布前检查\n\n- [ ] 所有测试通过\n- [ ] 文档已更新\n- [ ] CHANGELOG 已更新\n- [ ] 版本号正确\n- [ ] 破坏性变更已标记\n- [ ] 迁移指南已准备（如需要）\n\n## 发布后验证\n\n- [ ] npm 包可正常安装\n- [ ] 文档站已更新\n- [ ] 通知相关团队\n",[239],[405],{"type":24,"tag":101,"props":406,"children":407},{"__ignoreMap":7},[408],{"type":30,"value":402},{"type":24,"tag":25,"props":410,"children":412},{"id":411},"多版本支持",[413],{"type":30,"value":411},{"type":24,"tag":89,"props":415,"children":417},{"id":416},"长期支持策略",[418],{"type":30,"value":416},{"type":24,"tag":110,"props":420,"children":421},{},[422,443],{"type":24,"tag":114,"props":423,"children":424},{},[425],{"type":24,"tag":118,"props":426,"children":427},{},[428,433,438],{"type":24,"tag":122,"props":429,"children":430},{},[431],{"type":30,"value":432},"版本",{"type":24,"tag":122,"props":434,"children":435},{},[436],{"type":30,"value":437},"状态",{"type":24,"tag":122,"props":439,"children":440},{},[441],{"type":30,"value":442},"支持期限",{"type":24,"tag":138,"props":444,"children":445},{},[446,464,482],{"type":24,"tag":118,"props":447,"children":448},{},[449,454,459],{"type":24,"tag":145,"props":450,"children":451},{},[452],{"type":30,"value":453},"3.x",{"type":24,"tag":145,"props":455,"children":456},{},[457],{"type":30,"value":458},"Current",{"type":24,"tag":145,"props":460,"children":461},{},[462],{"type":30,"value":463},"持续更新",{"type":24,"tag":118,"props":465,"children":466},{},[467,472,477],{"type":24,"tag":145,"props":468,"children":469},{},[470],{"type":30,"value":471},"2.x",{"type":24,"tag":145,"props":473,"children":474},{},[475],{"type":30,"value":476},"LTS",{"type":24,"tag":145,"props":478,"children":479},{},[480],{"type":30,"value":481},"至 2025-06",{"type":24,"tag":118,"props":483,"children":484},{},[485,490,495],{"type":24,"tag":145,"props":486,"children":487},{},[488],{"type":30,"value":489},"1.x",{"type":24,"tag":145,"props":491,"children":492},{},[493],{"type":30,"value":494},"EOL",{"type":24,"tag":145,"props":496,"children":497},{},[498],{"type":30,"value":499},"不再维护",{"type":24,"tag":89,"props":501,"children":503},{"id":502},"分支管理",[504],{"type":30,"value":502},{"type":24,"tag":202,"props":506,"children":508},{"code":507},"main        → 最新开发版\nrelease/3.x → 当前稳定版\nrelease/2.x → LTS 版本\nrelease/1.x → 仅关键安全修复\n",[509],{"type":24,"tag":101,"props":510,"children":511},{"__ignoreMap":7},[512],{"type":30,"value":507},{"type":24,"tag":89,"props":514,"children":516},{"id":515},"回溯修复",[517],{"type":30,"value":515},{"type":24,"tag":202,"props":519,"children":522},{"code":520,"language":258,"meta":7,"className":521},"# Cherry-pick 修复到旧版本\ngit checkout release/2.x\ngit cherry-pick \u003Ccommit-hash>\ngit push origin release/2.x\n\n# 从 2.x 分支发布\nnpm version patch\nnpm publish --tag v2-lts\n",[260],[523],{"type":24,"tag":101,"props":524,"children":525},{"__ignoreMap":7},[526],{"type":30,"value":520},{"type":24,"tag":25,"props":528,"children":530},{"id":529},"版本依赖管理",[531],{"type":30,"value":529},{"type":24,"tag":89,"props":533,"children":535},{"id":534},"peer-dependencies",[536],{"type":30,"value":537},"Peer Dependencies",{"type":24,"tag":202,"props":539,"children":544},{"code":540,"language":541,"meta":7,"className":542},"{\n  \"peerDependencies\": {\n    \"vue\": \"^3.3.0\",\n    \"tailwindcss\": \"^3.0.0\"\n  },\n  \"peerDependenciesMeta\": {\n    \"tailwindcss\": {\n      \"optional\": true\n    }\n  }\n}\n","json",[543],"language-json",[545],{"type":24,"tag":101,"props":546,"children":547},{"__ignoreMap":7},[548],{"type":30,"value":540},{"type":24,"tag":89,"props":550,"children":552},{"id":551},"锁定依赖范围",[553],{"type":30,"value":551},{"type":24,"tag":202,"props":555,"children":558},{"code":556,"language":541,"meta":7,"className":557},"{\n  \"dependencies\": {\n    \"@floating-ui/vue\": \"^1.0.0\",\n    \"dayjs\": \"^1.11.0\"\n  },\n  \"devDependencies\": {\n    \"vue\": \"3.3.8\"\n  }\n}\n",[543],[559],{"type":24,"tag":101,"props":560,"children":561},{"__ignoreMap":7},[562],{"type":30,"value":556},{"type":24,"tag":25,"props":564,"children":566},{"id":565},"版本沟通",[567],{"type":30,"value":565},{"type":24,"tag":89,"props":569,"children":571},{"id":570},"发布公告模板",[572],{"type":30,"value":570},{"type":24,"tag":202,"props":574,"children":577},{"code":575,"language":237,"meta":7,"className":576},"# 🎉 Design System v2.5.0 发布\n\n## 新功能\n\n### DateRangePicker 日期范围选择器\n支持选择日期范围，适用于报表筛选等场景。\n\n```vue\n\u003CDateRangePicker v-model=\"dateRange\" />\n",[239],[578],{"type":24,"tag":101,"props":579,"children":580},{"__ignoreMap":7},[581],{"type":30,"value":575},{"type":24,"tag":89,"props":583,"children":585},{"id":584},"button-新增-loading-状态",[586],{"type":30,"value":587},"Button 新增 loading 状态",{"type":24,"tag":32,"props":589,"children":590},{},[591],{"type":30,"value":592},"点击后自动显示加载状态，防止重复提交。",{"type":24,"tag":25,"props":594,"children":596},{"id":595},"升级指南",[597],{"type":30,"value":595},{"type":24,"tag":202,"props":599,"children":602},{"code":600,"language":258,"meta":7,"className":601},"npm install @company/design-system@2.5.0\n",[260],[603],{"type":24,"tag":101,"props":604,"children":605},{"__ignoreMap":7},[606],{"type":30,"value":600},{"type":24,"tag":25,"props":608,"children":610},{"id":609},"完整变更日志",[611],{"type":30,"value":609},{"type":24,"tag":32,"props":613,"children":614},{},[615],{"type":30,"value":616},"查看 CHANGELOG.md",{"type":24,"tag":202,"props":618,"children":620},{"code":619},"\n### 废弃通知\n\n```markdown\n# ⚠️ 废弃通知\n\n## Input.clearable 属性\n\n`clearable` 属性将在 v3.0 移除。\n\n**迁移方法**：\n```diff\n- \u003CInput clearable />\n+ \u003CInput allowClear />\n",[621],{"type":24,"tag":101,"props":622,"children":623},{"__ignoreMap":7},[624],{"type":30,"value":619},{"type":24,"tag":32,"props":626,"children":627},{},[628,633],{"type":24,"tag":46,"props":629,"children":630},{},[631],{"type":30,"value":632},"废弃时间线",{"type":30,"value":321},{"type":24,"tag":38,"props":635,"children":636},{},[637,642,647],{"type":24,"tag":42,"props":638,"children":639},{},[640],{"type":30,"value":641},"v2.5: 添加废弃警告",{"type":24,"tag":42,"props":643,"children":644},{},[645],{"type":30,"value":646},"v2.8: 开发环境警告",{"type":24,"tag":42,"props":648,"children":649},{},[650],{"type":30,"value":651},"v3.0: 移除属性",{"type":24,"tag":202,"props":653,"children":655},{"code":654},"\n## 最佳实践\n\n| 原则 | 说明 |\n|-----|------|\n| 避免破坏性变更 | 优先向后兼容方案 |\n| 渐进式废弃 | 给用户迁移时间 |\n| 清晰的文档 | 变更日志 + 迁移指南 |\n| 自动化流程 | CI/CD 自动发布 |\n| 及时沟通 | 通知依赖项目 |\n\n## 总结\n\n设计系统版本管理的核心在于：\n\n1. **规范版本号** - 遵循语义化版本\n2. **记录变更** - 完整的变更日志\n3. **平滑迁移** - 废弃流程 + 迁移工具\n4. **自动化** - CI/CD 发布流程\n5. **有效沟通** - 及时通知和文档\n\n良好的版本管理让设计系统既保持创新又确保稳定。\n",[656],{"type":24,"tag":101,"props":657,"children":658},{"__ignoreMap":7},[659],{"type":30,"value":654},{"title":7,"searchDepth":661,"depth":661,"links":662},3,[663,665,670,674,679,683,688,692,696,697],{"id":27,"depth":664,"text":27},2,{"id":85,"depth":664,"text":85,"children":666},[667,668,669],{"id":91,"depth":661,"text":94},{"id":198,"depth":661,"text":198},{"id":212,"depth":661,"text":212},{"id":225,"depth":664,"text":225,"children":671},[672,673],{"id":230,"depth":661,"text":233},{"id":247,"depth":661,"text":247},{"id":279,"depth":664,"text":279,"children":675},[676,677,678],{"id":284,"depth":661,"text":284},{"id":300,"depth":661,"text":300},{"id":333,"depth":661,"text":336},{"id":376,"depth":664,"text":376,"children":680},[681,682],{"id":381,"depth":661,"text":381},{"id":397,"depth":661,"text":397},{"id":411,"depth":664,"text":411,"children":684},[685,686,687],{"id":416,"depth":661,"text":416},{"id":502,"depth":661,"text":502},{"id":515,"depth":661,"text":515},{"id":529,"depth":664,"text":529,"children":689},[690,691],{"id":534,"depth":661,"text":537},{"id":551,"depth":661,"text":551},{"id":565,"depth":664,"text":565,"children":693},[694,695],{"id":570,"depth":661,"text":570},{"id":584,"depth":661,"text":587},{"id":595,"depth":664,"text":595},{"id":609,"depth":664,"text":609},"content:topics:design:design-system-versioning-guide.md","content","topics/design/design-system-versioning-guide.md","topics/design/design-system-versioning-guide","md",[704,1060,1360],{"_path":705,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":706,"description":707,"keywords":708,"image":714,"author":11,"date":715,"readingTime":716,"topic":5,"body":717,"_type":237,"_id":1057,"_source":699,"_file":1058,"_stem":1059,"_extension":702},"/topics/design/button-component-design","按钮组件设计详解","学习按钮样式、交互状态、无障碍性和最佳实践",[709,710,711,712,713],"按钮设计","Button Component","交互状态","UI 组件","用户体验","/images/topics/button-design.jpg","2025-12-08",18,{"type":21,"children":718,"toc":1039},[719,723,728,733,739,750,756,765,771,780,784,790,801,807,816,822,831,836,845,850,861,866,875,880,892,926,937,980,985],{"type":24,"tag":25,"props":720,"children":721},{"id":706},[722],{"type":30,"value":706},{"type":24,"tag":32,"props":724,"children":725},{},[726],{"type":30,"value":727},"按钮是 UI 中最重要的交互元素。优秀的按钮设计能够指导用户行为。",{"type":24,"tag":25,"props":729,"children":731},{"id":730},"按钮类型",[732],{"type":30,"value":730},{"type":24,"tag":89,"props":734,"children":736},{"id":735},"primary-button主按钮",[737],{"type":30,"value":738},"Primary Button（主按钮）",{"type":24,"tag":202,"props":740,"children":745},{"className":741,"code":743,"language":744,"meta":7},[742],"language-css",".btn-primary {\n  background-color: #0066cc;\n  color: #ffffff;\n  padding: 12px 24px;\n  border: none;\n  border-radius: 4px;\n  font-weight: 600;\n  font-size: 16px;\n  cursor: pointer;\n  transition: all 0.2s ease;\n}\n\n.btn-primary:hover {\n  background-color: #0052a3;\n  box-shadow: 0 4px 12px rgba(0, 102, 204, 0.2);\n}\n\n.btn-primary:active {\n  background-color: #003d7a;\n  transform: scale(0.98);\n}\n\n.btn-primary:disabled {\n  background-color: #cccccc;\n  cursor: not-allowed;\n  opacity: 0.6;\n}\n","css",[746],{"type":24,"tag":101,"props":747,"children":748},{"__ignoreMap":7},[749],{"type":30,"value":743},{"type":24,"tag":89,"props":751,"children":753},{"id":752},"secondary-button次按钮",[754],{"type":30,"value":755},"Secondary Button（次按钮）",{"type":24,"tag":202,"props":757,"children":760},{"className":758,"code":759,"language":744,"meta":7},[742],".btn-secondary {\n  background-color: transparent;\n  color: #0066cc;\n  border: 2px solid #0066cc;\n  padding: 10px 22px;\n  border-radius: 4px;\n  font-weight: 600;\n  cursor: pointer;\n  transition: all 0.2s;\n}\n\n.btn-secondary:hover {\n  background-color: rgba(0, 102, 204, 0.1);\n}\n\n.btn-secondary:active {\n  background-color: rgba(0, 102, 204, 0.2);\n}\n",[761],{"type":24,"tag":101,"props":762,"children":763},{"__ignoreMap":7},[764],{"type":30,"value":759},{"type":24,"tag":89,"props":766,"children":768},{"id":767},"danger-button危险按钮",[769],{"type":30,"value":770},"Danger Button（危险按钮）",{"type":24,"tag":202,"props":772,"children":775},{"className":773,"code":774,"language":744,"meta":7},[742],".btn-danger {\n  background-color: #cc0000;\n  color: #ffffff;\n  padding: 12px 24px;\n  border-radius: 4px;\n  cursor: pointer;\n  font-weight: 600;\n}\n\n.btn-danger:hover {\n  background-color: #990000;\n  box-shadow: 0 4px 12px rgba(204, 0, 0, 0.2);\n}\n",[776],{"type":24,"tag":101,"props":777,"children":778},{"__ignoreMap":7},[779],{"type":30,"value":774},{"type":24,"tag":25,"props":781,"children":782},{"id":711},[783],{"type":30,"value":711},{"type":24,"tag":89,"props":785,"children":787},{"id":786},"loading-状态",[788],{"type":30,"value":789},"Loading 状态",{"type":24,"tag":202,"props":791,"children":796},{"className":792,"code":794,"language":795,"meta":7},[793],"language-jsx","import { useState } from 'react';\n\nfunction Button({ children, onClick, loading, ...props }) {\n  const [isLoading, setIsLoading] = useState(false);\n  \n  const handleClick = async () => {\n    setIsLoading(true);\n    try {\n      await onClick();\n    } finally {\n      setIsLoading(false);\n    }\n  };\n  \n  return (\n    \u003Cbutton\n      onClick={handleClick}\n      disabled={isLoading || loading}\n      aria-busy={isLoading || loading}\n      {...props}\n    >\n      {isLoading ? (\n        \u003C>\n          \u003Cspan className=\"spinner\" aria-hidden=\"true\">\u003C/span>\n          {children}\n        \u003C/>\n      ) : (\n        children\n      )}\n    \u003C/button>\n  );\n}\n","jsx",[797],{"type":24,"tag":101,"props":798,"children":799},{"__ignoreMap":7},[800],{"type":30,"value":794},{"type":24,"tag":89,"props":802,"children":804},{"id":803},"disabled-状态",[805],{"type":30,"value":806},"Disabled 状态",{"type":24,"tag":202,"props":808,"children":811},{"className":809,"code":810,"language":744,"meta":7},[742],".btn:disabled {\n  opacity: 0.5;\n  cursor: not-allowed;\n  background-color: #cccccc;\n  color: #999999;\n}\n\n/* 禁用状态下隐藏指针光标 */\n.btn:disabled:hover {\n  box-shadow: none;\n  transform: none;\n}\n",[812],{"type":24,"tag":101,"props":813,"children":814},{"__ignoreMap":7},[815],{"type":30,"value":810},{"type":24,"tag":89,"props":817,"children":819},{"id":818},"focus-状态",[820],{"type":30,"value":821},"Focus 状态",{"type":24,"tag":202,"props":823,"children":826},{"className":824,"code":825,"language":744,"meta":7},[742],".btn:focus {\n  outline: none;\n  box-shadow: 0 0 0 3px rgba(0, 102, 204, 0.1),\n              0 0 0 5px #0066cc;\n}\n\n/* 键盘导航焦点 */\n.btn:focus-visible {\n  outline: 2px solid #0066cc;\n  outline-offset: 2px;\n}\n",[827],{"type":24,"tag":101,"props":828,"children":829},{"__ignoreMap":7},[830],{"type":30,"value":825},{"type":24,"tag":25,"props":832,"children":834},{"id":833},"按钮大小",[835],{"type":30,"value":833},{"type":24,"tag":202,"props":837,"children":840},{"className":838,"code":839,"language":744,"meta":7},[742],"/* 小按钮 */\n.btn-sm {\n  padding: 6px 12px;\n  font-size: 12px;\n  min-height: 32px;\n  min-width: 32px;\n}\n\n/* 中等按钮（默认） */\n.btn-md {\n  padding: 12px 24px;\n  font-size: 16px;\n  min-height: 44px;\n  min-width: 44px;\n}\n\n/* 大按钮 */\n.btn-lg {\n  padding: 16px 32px;\n  font-size: 18px;\n  min-height: 56px;\n  min-width: 56px;\n}\n\n/* 全宽按钮 */\n.btn-block {\n  width: 100%;\n  display: block;\n}\n",[841],{"type":24,"tag":101,"props":842,"children":843},{"__ignoreMap":7},[844],{"type":30,"value":839},{"type":24,"tag":25,"props":846,"children":848},{"id":847},"无障碍性",[849],{"type":30,"value":847},{"type":24,"tag":202,"props":851,"children":856},{"className":852,"code":854,"language":855,"meta":7},[853],"language-html","\u003C!-- 语义正确 -->\n\u003Cbutton type=\"submit\" aria-label=\"提交表单\">\n  提交\n\u003C/button>\n\n\u003C!-- 加载状态 -->\n\u003Cbutton aria-busy=\"true\" disabled>\n  \u003Cspan aria-hidden=\"true\" class=\"spinner\">\u003C/span>\n  加载中...\n\u003C/button>\n\n\u003C!-- 图标按钮 -->\n\u003Cbutton aria-label=\"关闭\">\n  \u003Csvg aria-hidden=\"true\" width=\"24\" height=\"24\">\n    \u003Cline x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n    \u003Cline x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n  \u003C/svg>\n\u003C/button>\n\n\u003C!-- 切换按钮 -->\n\u003Cbutton aria-pressed=\"false\" aria-label=\"点赞\">\n  ♥\n\u003C/button>\n","html",[857],{"type":24,"tag":101,"props":858,"children":859},{"__ignoreMap":7},[860],{"type":30,"value":854},{"type":24,"tag":25,"props":862,"children":864},{"id":863},"完整组件示例",[865],{"type":30,"value":863},{"type":24,"tag":202,"props":867,"children":870},{"className":868,"code":869,"language":795,"meta":7},[793],"const Button = React.forwardRef((\n  {\n    children,\n    variant = 'primary',\n    size = 'md',\n    loading = false,\n    disabled = false,\n    icon,\n    className,\n    ...props\n  },\n  ref\n) => {\n  return (\n    \u003Cbutton\n      ref={ref}\n      className={`btn btn-${variant} btn-${size} ${className}`}\n      disabled={disabled || loading}\n      aria-busy={loading}\n      {...props}\n    >\n      {icon && \u003Cspan className=\"btn-icon\" aria-hidden=\"true\">{icon}\u003C/span>}\n      {loading ? (\n        \u003C>\n          \u003Cspan className=\"spinner\" aria-hidden=\"true\">\u003C/span>\n          {children}\n        \u003C/>\n      ) : (\n        children\n      )}\n    \u003C/button>\n  );\n});\n\nButton.displayName = 'Button';\n",[871],{"type":24,"tag":101,"props":872,"children":873},{"__ignoreMap":7},[874],{"type":30,"value":869},{"type":24,"tag":25,"props":876,"children":878},{"id":877},"最佳实践",[879],{"type":30,"value":877},{"type":24,"tag":32,"props":881,"children":882},{},[883,885,890],{"type":30,"value":884},"✅ ",{"type":24,"tag":46,"props":886,"children":887},{},[888],{"type":30,"value":889},"应该做的事",{"type":30,"value":891},":",{"type":24,"tag":38,"props":893,"children":894},{},[895,900,905,916,921],{"type":24,"tag":42,"props":896,"children":897},{},[898],{"type":30,"value":899},"最小触摸目标 44x44px",{"type":24,"tag":42,"props":901,"children":902},{},[903],{"type":30,"value":904},"清晰的视觉反馈",{"type":24,"tag":42,"props":906,"children":907},{},[908,910],{"type":30,"value":909},"使用语义 HTML ",{"type":24,"tag":101,"props":911,"children":913},{"className":912},[],[914],{"type":30,"value":915},"\u003Cbutton>",{"type":24,"tag":42,"props":917,"children":918},{},[919],{"type":30,"value":920},"提供加载状态反馈",{"type":24,"tag":42,"props":922,"children":923},{},[924],{"type":30,"value":925},"支持键盘导航",{"type":24,"tag":32,"props":927,"children":928},{},[929,931,936],{"type":30,"value":930},"❌ ",{"type":24,"tag":46,"props":932,"children":933},{},[934],{"type":30,"value":935},"不应该做的事",{"type":30,"value":891},{"type":24,"tag":38,"props":938,"children":939},{},[940,953,958,963,968],{"type":24,"tag":42,"props":941,"children":942},{},[943,945,951],{"type":30,"value":944},"使用 ",{"type":24,"tag":101,"props":946,"children":948},{"className":947},[],[949],{"type":30,"value":950},"\u003Cdiv>",{"type":30,"value":952}," 模拟按钮",{"type":24,"tag":42,"props":954,"children":955},{},[956],{"type":30,"value":957},"隐藏焦点指示器",{"type":24,"tag":42,"props":959,"children":960},{},[961],{"type":30,"value":962},"过多的按钮样式",{"type":24,"tag":42,"props":964,"children":965},{},[966],{"type":30,"value":967},"忽视禁用状态",{"type":24,"tag":42,"props":969,"children":970},{},[971,972,978],{"type":30,"value":944},{"type":24,"tag":101,"props":973,"children":975},{"className":974},[],[976],{"type":30,"value":977},"\u003Ca>",{"type":30,"value":979}," 代替按钮",{"type":24,"tag":25,"props":981,"children":983},{"id":982},"测试清单",[984],{"type":30,"value":982},{"type":24,"tag":38,"props":986,"children":989},{"className":987},[988],"contains-task-list",[990,1003,1012,1021,1030],{"type":24,"tag":42,"props":991,"children":994},{"className":992},[993],"task-list-item",[995,1001],{"type":24,"tag":996,"props":997,"children":1000},"input",{"disabled":998,"type":999},true,"checkbox",[],{"type":30,"value":1002}," 在各种浏览器中测试",{"type":24,"tag":42,"props":1004,"children":1006},{"className":1005},[993],[1007,1010],{"type":24,"tag":996,"props":1008,"children":1009},{"disabled":998,"type":999},[],{"type":30,"value":1011}," 验证键盘导航",{"type":24,"tag":42,"props":1013,"children":1015},{"className":1014},[993],[1016,1019],{"type":24,"tag":996,"props":1017,"children":1018},{"disabled":998,"type":999},[],{"type":30,"value":1020}," 检查色彩对比度",{"type":24,"tag":42,"props":1022,"children":1024},{"className":1023},[993],[1025,1028],{"type":24,"tag":996,"props":1026,"children":1027},{"disabled":998,"type":999},[],{"type":30,"value":1029}," 测试触摸设备",{"type":24,"tag":42,"props":1031,"children":1033},{"className":1032},[993],[1034,1037],{"type":24,"tag":996,"props":1035,"children":1036},{"disabled":998,"type":999},[],{"type":30,"value":1038}," 屏幕阅读器兼容性",{"title":7,"searchDepth":661,"depth":661,"links":1040},[1041,1042,1047,1052,1053,1054,1055,1056],{"id":706,"depth":664,"text":706},{"id":730,"depth":664,"text":730,"children":1043},[1044,1045,1046],{"id":735,"depth":661,"text":738},{"id":752,"depth":661,"text":755},{"id":767,"depth":661,"text":770},{"id":711,"depth":664,"text":711,"children":1048},[1049,1050,1051],{"id":786,"depth":661,"text":789},{"id":803,"depth":661,"text":806},{"id":818,"depth":661,"text":821},{"id":833,"depth":664,"text":833},{"id":847,"depth":664,"text":847},{"id":863,"depth":664,"text":863},{"id":877,"depth":664,"text":877},{"id":982,"depth":664,"text":982},"content:topics:design:button-component-design.md","topics/design/button-component-design.md","topics/design/button-component-design",{"_path":1061,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":1062,"description":1063,"keywords":1064,"image":1069,"author":11,"date":715,"readingTime":1070,"topic":5,"body":1071,"_type":237,"_id":1357,"_source":699,"_file":1358,"_stem":1359,"_extension":702},"/topics/design/dark-mode-design","暗黑模式设计完整方案","学习暗黑模式实现、色彩方案、对比度管理和最佳实践",[1065,1066,1067,1068,713],"暗黑模式","Dark Mode","色彩系统","CSS 变量","/images/topics/dark-mode-design.jpg",20,{"type":21,"children":1072,"toc":1340},[1073,1077,1082,1087,1093,1102,1108,1117,1122,1128,1137,1143,1152,1158,1167,1172,1181,1186,1195,1200,1209,1213,1222,1250,1259,1287,1291],{"type":24,"tag":25,"props":1074,"children":1075},{"id":1062},[1076],{"type":30,"value":1062},{"type":24,"tag":32,"props":1078,"children":1079},{},[1080],{"type":30,"value":1081},"暗黑模式已成为现代应用的标准功能。它能够减少眼睛疲劳、节省电池、改善用户体验。",{"type":24,"tag":25,"props":1083,"children":1085},{"id":1084},"核心色彩系统",[1086],{"type":30,"value":1084},{"type":24,"tag":89,"props":1088,"children":1090},{"id":1089},"light-mode-配色",[1091],{"type":30,"value":1092},"Light Mode 配色",{"type":24,"tag":202,"props":1094,"children":1097},{"className":1095,"code":1096,"language":744,"meta":7},[742],":root {\n  /* Light Mode */\n  --bg-primary: #ffffff;\n  --bg-secondary: #f5f5f5;\n  --bg-tertiary: #efefef;\n  \n  --text-primary: #1a1a1a;\n  --text-secondary: #666666;\n  --text-tertiary: #999999;\n  \n  --border-color: #e0e0e0;\n  --divider-color: #f0f0f0;\n}\n",[1098],{"type":24,"tag":101,"props":1099,"children":1100},{"__ignoreMap":7},[1101],{"type":30,"value":1096},{"type":24,"tag":89,"props":1103,"children":1105},{"id":1104},"dark-mode-配色",[1106],{"type":30,"value":1107},"Dark Mode 配色",{"type":24,"tag":202,"props":1109,"children":1112},{"className":1110,"code":1111,"language":744,"meta":7},[742],"@media (prefers-color-scheme: dark) {\n  :root {\n    /* Dark Mode */\n    --bg-primary: #1a1a1a;\n    --bg-secondary: #2d2d2d;\n    --bg-tertiary: #3a3a3a;\n    \n    --text-primary: #ffffff;\n    --text-secondary: #e0e0e0;\n    --text-tertiary: #a0a0a0;\n    \n    --border-color: #404040;\n    --divider-color: #2a2a2a;\n  }\n}\n",[1113],{"type":24,"tag":101,"props":1114,"children":1115},{"__ignoreMap":7},[1116],{"type":30,"value":1111},{"type":24,"tag":25,"props":1118,"children":1120},{"id":1119},"实现方案",[1121],{"type":30,"value":1119},{"type":24,"tag":89,"props":1123,"children":1125},{"id":1124},"方案-1prefers-color-scheme",[1126],{"type":30,"value":1127},"方案 1：prefers-color-scheme",{"type":24,"tag":202,"props":1129,"children":1132},{"className":1130,"code":1131,"language":744,"meta":7},[742],"/* 自动跟随系统设置 */\n@media (prefers-color-scheme: light) {\n  :root {\n    --bg: #fff;\n    --text: #000;\n  }\n}\n\n@media (prefers-color-scheme: dark) {\n  :root {\n    --bg: #1a1a1a;\n    --text: #fff;\n  }\n}\n\nbody {\n  background: var(--bg);\n  color: var(--text);\n}\n",[1133],{"type":24,"tag":101,"props":1134,"children":1135},{"__ignoreMap":7},[1136],{"type":30,"value":1131},{"type":24,"tag":89,"props":1138,"children":1140},{"id":1139},"方案-2javascript-切换",[1141],{"type":30,"value":1142},"方案 2：JavaScript 切换",{"type":24,"tag":202,"props":1144,"children":1147},{"className":1145,"code":1146,"language":269,"meta":7},[271],"// 检测和切换暗黑模式\nfunction initDarkMode() {\n  const isDark = localStorage.getItem('darkMode') === 'true' ||\n                 window.matchMedia('(prefers-color-scheme: dark)').matches;\n  \n  if (isDark) {\n    document.documentElement.setAttribute('data-theme', 'dark');\n  }\n}\n\nfunction toggleDarkMode() {\n  const isDark = document.documentElement.getAttribute('data-theme') === 'dark';\n  const newTheme = isDark ? 'light' : 'dark';\n  \n  document.documentElement.setAttribute('data-theme', newTheme);\n  localStorage.setItem('darkMode', newTheme === 'dark');\n}\n\n// CSS 应用\nhtml[data-theme='light'] {\n  color-scheme: light;\n}\n\nhtml[data-theme='dark'] {\n  color-scheme: dark;\n}\n",[1148],{"type":24,"tag":101,"props":1149,"children":1150},{"__ignoreMap":7},[1151],{"type":30,"value":1146},{"type":24,"tag":89,"props":1153,"children":1155},{"id":1154},"方案-3css-variables-javascript",[1156],{"type":30,"value":1157},"方案 3：CSS Variables + JavaScript",{"type":24,"tag":202,"props":1159,"children":1162},{"className":1160,"code":1161,"language":269,"meta":7},[271],"const themes = {\n  light: {\n    '--bg-primary': '#ffffff',\n    '--text-primary': '#000000',\n    '--accent': '#0066cc',\n    '--border': '#e0e0e0',\n  },\n  dark: {\n    '--bg-primary': '#1a1a1a',\n    '--text-primary': '#ffffff',\n    '--accent': '#4da3ff',\n    '--border': '#404040',\n  },\n};\n\nfunction applyTheme(themeName) {\n  const theme = themes[themeName];\n  Object.entries(theme).forEach(([key, value]) => {\n    document.documentElement.style.setProperty(key, value);\n  });\n  localStorage.setItem('theme', themeName);\n}\n",[1163],{"type":24,"tag":101,"props":1164,"children":1165},{"__ignoreMap":7},[1166],{"type":30,"value":1161},{"type":24,"tag":25,"props":1168,"children":1170},{"id":1169},"对比度管理",[1171],{"type":30,"value":1169},{"type":24,"tag":202,"props":1173,"children":1176},{"className":1174,"code":1175,"language":744,"meta":7},[742],"/* Light Mode 对比度 */\n:root {\n  --contrast-high: #000000;     /* 21:1 */\n  --contrast-medium: #333333;   /* 12.6:1 */\n  --contrast-low: #666666;      /* 5.1:1 */\n}\n\n/* Dark Mode 对比度 */\n@media (prefers-color-scheme: dark) {\n  :root {\n    --contrast-high: #ffffff;    /* 21:1 */\n    --contrast-medium: #e0e0e0;  /* 11.6:1 */\n    --contrast-low: #a0a0a0;     /* 4.5:1 */\n  }\n}\n\n/* 应用对比度 */\n.text-primary { color: var(--contrast-high); }\n.text-secondary { color: var(--contrast-medium); }\n.text-tertiary { color: var(--contrast-low); }\n",[1177],{"type":24,"tag":101,"props":1178,"children":1179},{"__ignoreMap":7},[1180],{"type":30,"value":1175},{"type":24,"tag":25,"props":1182,"children":1184},{"id":1183},"图片和图表处理",[1185],{"type":30,"value":1183},{"type":24,"tag":202,"props":1187,"children":1190},{"className":1188,"code":1189,"language":855,"meta":7},[853],"\u003C!-- 针对不同主题的图片 -->\n\u003Cpicture>\n  \u003Csource \n    media=\"(prefers-color-scheme: dark)\" \n    srcset=\"chart-dark.svg\"\n  />\n  \u003Cimg src=\"chart-light.svg\" alt=\"图表\" />\n\u003C/picture>\n\n\u003C!-- SVG 颜色适配 -->\n\u003Csvg class=\"icon\">\n  \u003Ccircle cx=\"50\" cy=\"50\" r=\"40\" fill=\"currentColor\" />\n\u003C/svg>\n\n\u003Cstyle>\n  .icon {\n    color: var(--text-primary);\n  }\n\u003C/style>\n",[1191],{"type":24,"tag":101,"props":1192,"children":1193},{"__ignoreMap":7},[1194],{"type":30,"value":1189},{"type":24,"tag":25,"props":1196,"children":1198},{"id":1197},"完整示例",[1199],{"type":30,"value":1197},{"type":24,"tag":202,"props":1201,"children":1204},{"className":1202,"code":1203,"language":795,"meta":7},[793],"import { useState, useEffect } from 'react';\n\nfunction ThemeProvider({ children }) {\n  const [theme, setTheme] = useState('light');\n  const [mounted, setMounted] = useState(false);\n  \n  useEffect(() => {\n    setMounted(true);\n    \n    // 获取保存的主题或系统偏好\n    const savedTheme = localStorage.getItem('theme');\n    const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches \n      ? 'dark' \n      : 'light';\n    \n    const initialTheme = savedTheme || systemTheme;\n    setTheme(initialTheme);\n    document.documentElement.setAttribute('data-theme', initialTheme);\n  }, []);\n  \n  const toggleTheme = () => {\n    const newTheme = theme === 'light' ? 'dark' : 'light';\n    setTheme(newTheme);\n    localStorage.setItem('theme', newTheme);\n    document.documentElement.setAttribute('data-theme', newTheme);\n  };\n  \n  // 防止闪烁\n  if (!mounted) {\n    return null;\n  }\n  \n  return (\n    \u003CThemeContext.Provider value={{ theme, toggleTheme }}>\n      {children}\n      \u003CThemeToggle theme={theme} onChange={toggleTheme} />\n    \u003C/ThemeContext.Provider>\n  );\n}\n\nfunction ThemeToggle({ theme, onChange }) {\n  return (\n    \u003Cbutton \n      onClick={onChange}\n      aria-label={`切换到${theme === 'light' ? '暗黑' : '亮色'}模式`}\n    >\n      {theme === 'light' ? '🌙' : '☀️'}\n    \u003C/button>\n  );\n}\n",[1205],{"type":24,"tag":101,"props":1206,"children":1207},{"__ignoreMap":7},[1208],{"type":30,"value":1203},{"type":24,"tag":25,"props":1210,"children":1211},{"id":877},[1212],{"type":30,"value":877},{"type":24,"tag":32,"props":1214,"children":1215},{},[1216,1217,1221],{"type":30,"value":884},{"type":24,"tag":46,"props":1218,"children":1219},{},[1220],{"type":30,"value":889},{"type":30,"value":891},{"type":24,"tag":38,"props":1223,"children":1224},{},[1225,1230,1235,1240,1245],{"type":24,"tag":42,"props":1226,"children":1227},{},[1228],{"type":30,"value":1229},"支持系统偏好",{"type":24,"tag":42,"props":1231,"children":1232},{},[1233],{"type":30,"value":1234},"提供手动切换选项",{"type":24,"tag":42,"props":1236,"children":1237},{},[1238],{"type":30,"value":1239},"确保足够的对比度",{"type":24,"tag":42,"props":1241,"children":1242},{},[1243],{"type":30,"value":1244},"优化图片和图表",{"type":24,"tag":42,"props":1246,"children":1247},{},[1248],{"type":30,"value":1249},"防止加载闪烁",{"type":24,"tag":32,"props":1251,"children":1252},{},[1253,1254,1258],{"type":30,"value":930},{"type":24,"tag":46,"props":1255,"children":1256},{},[1257],{"type":30,"value":935},{"type":30,"value":891},{"type":24,"tag":38,"props":1260,"children":1261},{},[1262,1267,1272,1277,1282],{"type":24,"tag":42,"props":1263,"children":1264},{},[1265],{"type":30,"value":1266},"强制单一模式",{"type":24,"tag":42,"props":1268,"children":1269},{},[1270],{"type":30,"value":1271},"忽视性能影响",{"type":24,"tag":42,"props":1273,"children":1274},{},[1275],{"type":30,"value":1276},"使用相同的颜色",{"type":24,"tag":42,"props":1278,"children":1279},{},[1280],{"type":30,"value":1281},"忘记保存用户偏好",{"type":24,"tag":42,"props":1283,"children":1284},{},[1285],{"type":30,"value":1286},"过度使用深色背景",{"type":24,"tag":25,"props":1288,"children":1289},{"id":982},[1290],{"type":30,"value":982},{"type":24,"tag":38,"props":1292,"children":1294},{"className":1293},[988],[1295,1304,1313,1322,1331],{"type":24,"tag":42,"props":1296,"children":1298},{"className":1297},[993],[1299,1302],{"type":24,"tag":996,"props":1300,"children":1301},{"disabled":998,"type":999},[],{"type":30,"value":1303}," 在浅色和深色模式下测试所有页面",{"type":24,"tag":42,"props":1305,"children":1307},{"className":1306},[993],[1308,1311],{"type":24,"tag":996,"props":1309,"children":1310},{"disabled":998,"type":999},[],{"type":30,"value":1312}," 检查颜色对比度符合 WCAG 标准",{"type":24,"tag":42,"props":1314,"children":1316},{"className":1315},[993],[1317,1320],{"type":24,"tag":996,"props":1318,"children":1319},{"disabled":998,"type":999},[],{"type":30,"value":1321}," 验证图片和图表在两种模式下清晰",{"type":24,"tag":42,"props":1323,"children":1325},{"className":1324},[993],[1326,1329],{"type":24,"tag":996,"props":1327,"children":1328},{"disabled":998,"type":999},[],{"type":30,"value":1330}," 测试主题切换的平滑性",{"type":24,"tag":42,"props":1332,"children":1334},{"className":1333},[993],[1335,1338],{"type":24,"tag":996,"props":1336,"children":1337},{"disabled":998,"type":999},[],{"type":30,"value":1339}," 检查用户偏好是否被保存",{"title":7,"searchDepth":661,"depth":661,"links":1341},[1342,1343,1347,1352,1353,1354,1355,1356],{"id":1062,"depth":664,"text":1062},{"id":1084,"depth":664,"text":1084,"children":1344},[1345,1346],{"id":1089,"depth":661,"text":1092},{"id":1104,"depth":661,"text":1107},{"id":1119,"depth":664,"text":1119,"children":1348},[1349,1350,1351],{"id":1124,"depth":661,"text":1127},{"id":1139,"depth":661,"text":1142},{"id":1154,"depth":661,"text":1157},{"id":1169,"depth":664,"text":1169},{"id":1183,"depth":664,"text":1183},{"id":1197,"depth":664,"text":1197},{"id":877,"depth":664,"text":877},{"id":982,"depth":664,"text":982},"content:topics:design:dark-mode-design.md","topics/design/dark-mode-design.md","topics/design/dark-mode-design",{"_path":1361,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":1362,"description":1363,"keywords":1364,"image":1369,"author":1370,"date":715,"readingTime":1070,"topic":5,"body":1371,"_type":237,"_id":1636,"_source":699,"_file":1637,"_stem":1638,"_extension":702},"/topics/design/form-controls-design","表单控件设计规范","学习输入框、选择框、复选框等表单控件的设计和实现",[1365,1366,1367,1368,713],"表单设计","Form Controls","输入框","验证反馈","/images/topics/form-controls-design.jpg","AI Content Team",{"type":21,"children":1372,"toc":1622},[1373,1377,1382,1387,1392,1401,1406,1415,1419,1428,1433,1442,1447,1456,1461,1470,1475,1484,1488,1497,1523,1532,1560,1564],{"type":24,"tag":25,"props":1374,"children":1375},{"id":1362},[1376],{"type":30,"value":1362},{"type":24,"tag":32,"props":1378,"children":1379},{},[1380],{"type":30,"value":1381},"优秀的表单设计能够提高用户完成率和满意度。",{"type":24,"tag":25,"props":1383,"children":1385},{"id":1384},"输入框设计",[1386],{"type":30,"value":1384},{"type":24,"tag":89,"props":1388,"children":1390},{"id":1389},"基础文本输入",[1391],{"type":30,"value":1389},{"type":24,"tag":202,"props":1393,"children":1396},{"className":1394,"code":1395,"language":744,"meta":7},[742],".input {\n  width: 100%;\n  padding: 12px 16px;\n  font-size: 16px;\n  border: 2px solid #e0e0e0;\n  border-radius: 4px;\n  font-family: inherit;\n  transition: border-color 0.2s;\n}\n\n.input:hover {\n  border-color: #bdbdbd;\n}\n\n.input:focus {\n  outline: none;\n  border-color: #0066cc;\n  box-shadow: 0 0 0 3px rgba(0, 102, 204, 0.1);\n}\n\n.input:disabled {\n  background-color: #f5f5f5;\n  color: #999999;\n  cursor: not-allowed;\n}\n\n.input.error {\n  border-color: #cc0000;\n}\n\n.input.success {\n  border-color: #00cc00;\n}\n",[1397],{"type":24,"tag":101,"props":1398,"children":1399},{"__ignoreMap":7},[1400],{"type":30,"value":1395},{"type":24,"tag":89,"props":1402,"children":1404},{"id":1403},"标签和提示",[1405],{"type":30,"value":1403},{"type":24,"tag":202,"props":1407,"children":1410},{"className":1408,"code":1409,"language":855,"meta":7},[853],"\u003Cdiv class=\"form-group\">\n  \u003Clabel for=\"email\" class=\"form-label\">\n    邮箱地址 \u003Cspan class=\"required\">*\u003C/span>\n  \u003C/label>\n  \u003Cinput\n    id=\"email\"\n    type=\"email\"\n    placeholder=\"user@example.com\"\n    class=\"input\"\n    aria-describedby=\"email-hint\"\n  />\n  \u003Cp id=\"email-hint\" class=\"form-hint\">\n    我们永远不会分享你的邮箱\n  \u003C/p>\n\u003C/div>\n",[1411],{"type":24,"tag":101,"props":1412,"children":1413},{"__ignoreMap":7},[1414],{"type":30,"value":1409},{"type":24,"tag":25,"props":1416,"children":1417},{"id":1368},[1418],{"type":30,"value":1368},{"type":24,"tag":202,"props":1420,"children":1423},{"className":1421,"code":1422,"language":795,"meta":7},[793],"function FormInput({ label, error, success, helperText, value, onChange, ...props }) {\n  return (\n    \u003Cdiv className=\"form-group\">\n      \u003Clabel className=\"form-label\">{label}\u003C/label>\n      \u003Cinput\n        className={`input ${\n          error ? 'error' : success ? 'success' : ''\n        }`}\n        value={value}\n        onChange={onChange}\n        {...props}\n      />\n      {error && (\n        \u003Cp className=\"form-error\" role=\"alert\">\n          {error}\n        \u003C/p>\n      )}\n      {success && (\n        \u003Cp className=\"form-success\">\n          ✓ {success}\n        \u003C/p>\n      )}\n      {helperText && (\n        \u003Cp className=\"form-hint\">{helperText}\u003C/p>\n      )}\n    \u003C/div>\n  );\n}\n",[1424],{"type":24,"tag":101,"props":1425,"children":1426},{"__ignoreMap":7},[1427],{"type":30,"value":1422},{"type":24,"tag":25,"props":1429,"children":1431},{"id":1430},"选择框设计",[1432],{"type":30,"value":1430},{"type":24,"tag":202,"props":1434,"children":1437},{"className":1435,"code":1436,"language":744,"meta":7},[742],".select {\n  appearance: none;\n  width: 100%;\n  padding: 12px 16px;\n  border: 2px solid #e0e0e0;\n  border-radius: 4px;\n  background-image: url('data:image/svg+xml;...');\n  background-repeat: no-repeat;\n  background-position: right 12px center;\n  padding-right: 40px;\n  font-size: 16px;\n  cursor: pointer;\n}\n\n.select:hover {\n  border-color: #bdbdbd;\n}\n\n.select:focus {\n  outline: none;\n  border-color: #0066cc;\n  box-shadow: 0 0 0 3px rgba(0, 102, 204, 0.1);\n}\n",[1438],{"type":24,"tag":101,"props":1439,"children":1440},{"__ignoreMap":7},[1441],{"type":30,"value":1436},{"type":24,"tag":25,"props":1443,"children":1445},{"id":1444},"复选框和单选按钮",[1446],{"type":30,"value":1444},{"type":24,"tag":202,"props":1448,"children":1451},{"className":1449,"code":1450,"language":744,"meta":7},[742],".checkbox-group {\n  display: flex;\n  gap: 12px;\n  align-items: center;\n}\n\n.checkbox-input {\n  width: 20px;\n  height: 20px;\n  cursor: pointer;\n  accent-color: #0066cc;\n}\n\n.checkbox-label {\n  cursor: pointer;\n  user-select: none;\n}\n\n/* 自定义复选框 */\n.custom-checkbox {\n  appearance: none;\n  width: 20px;\n  height: 20px;\n  border: 2px solid #e0e0e0;\n  border-radius: 4px;\n  cursor: pointer;\n  background-color: white;\n  transition: all 0.2s;\n}\n\n.custom-checkbox:checked {\n  background-color: #0066cc;\n  border-color: #0066cc;\n  background-image: url('data:image/svg+xml;...');\n}\n\n.custom-checkbox:focus {\n  box-shadow: 0 0 0 3px rgba(0, 102, 204, 0.1);\n}\n",[1452],{"type":24,"tag":101,"props":1453,"children":1454},{"__ignoreMap":7},[1455],{"type":30,"value":1450},{"type":24,"tag":25,"props":1457,"children":1459},{"id":1458},"文本区域",[1460],{"type":30,"value":1458},{"type":24,"tag":202,"props":1462,"children":1465},{"className":1463,"code":1464,"language":744,"meta":7},[742],".textarea {\n  width: 100%;\n  min-height: 120px;\n  padding: 12px 16px;\n  border: 2px solid #e0e0e0;\n  border-radius: 4px;\n  font-family: inherit;\n  font-size: 16px;\n  resize: vertical;\n  transition: border-color 0.2s;\n}\n\n.textarea:focus {\n  outline: none;\n  border-color: #0066cc;\n  box-shadow: 0 0 0 3px rgba(0, 102, 204, 0.1);\n}\n",[1466],{"type":24,"tag":101,"props":1467,"children":1468},{"__ignoreMap":7},[1469],{"type":30,"value":1464},{"type":24,"tag":25,"props":1471,"children":1473},{"id":1472},"完整表单示例",[1474],{"type":30,"value":1472},{"type":24,"tag":202,"props":1476,"children":1479},{"className":1477,"code":1478,"language":795,"meta":7},[793],"function SignupForm() {\n  const [formData, setFormData] = useState({\n    name: '',\n    email: '',\n    password: '',\n    confirmPassword: '',\n    subscribe: false,\n    terms: false,\n  });\n  \n  const [errors, setErrors] = useState({});\n  const [touched, setTouched] = useState({});\n  const [submitted, setSubmitted] = useState(false);\n  \n  const handleChange = (e) => {\n    const { name, value, type, checked } = e.target;\n    setFormData(prev => ({\n      ...prev,\n      [name]: type === 'checkbox' ? checked : value,\n    }));\n    \n    // 实时验证\n    if (touched[name]) {\n      validateField(name, type === 'checkbox' ? checked : value);\n    }\n  };\n  \n  const handleBlur = (e) => {\n    const { name } = e.target;\n    setTouched(prev => ({ ...prev, [name]: true }));\n    validateField(name, formData[name]);\n  };\n  \n  const validateField = (name, value) => {\n    const newErrors = { ...errors };\n    \n    switch (name) {\n      case 'name':\n        if (!value) newErrors.name = '名字不能为空';\n        else delete newErrors.name;\n        break;\n      case 'email':\n        if (!value) newErrors.email = '邮箱不能为空';\n        else if (!/^[^\\\\s@]+@[^\\\\s@]+\\\\.[^\\\\s@]+$/.test(value)) {\n          newErrors.email = '请输入有效的邮箱';\n        } else {\n          delete newErrors.email;\n        }\n        break;\n      case 'password':\n        if (!value) newErrors.password = '密码不能为空';\n        else if (value.length \u003C 8) newErrors.password = '密码至少 8 位';\n        else delete newErrors.password;\n        break;\n      case 'confirmPassword':\n        if (value !== formData.password) {\n          newErrors.confirmPassword = '两次密码输入不一致';\n        } else {\n          delete newErrors.confirmPassword;\n        }\n        break;\n      case 'terms':\n        if (!value) newErrors.terms = '必须同意服务条款';\n        else delete newErrors.terms;\n        break;\n      default:\n        break;\n    }\n    \n    setErrors(newErrors);\n  };\n  \n  const validate = () => {\n    const newErrors = {};\n    \n    if (!formData.name) newErrors.name = '名字不能为空';\n    if (!formData.email) newErrors.email = '邮箱不能为空';\n    if (formData.password.length \u003C 8) newErrors.password = '密码至少 8 位';\n    if (formData.password !== formData.confirmPassword) {\n      newErrors.confirmPassword = '两次密码输入不一致';\n    }\n    if (!formData.terms) newErrors.terms = '必须同意服务条款';\n    \n    return newErrors;\n  };\n  \n  const handleSubmit = async (e) => {\n    e.preventDefault();\n    \n    // 标记所有字段已触碰\n    setTouched({\n      name: true,\n      email: true,\n      password: true,\n      confirmPassword: true,\n      terms: true,\n    });\n    \n    const newErrors = validate();\n    \n    if (Object.keys(newErrors).length === 0) {\n      setSubmitted(true);\n      // 提交表单\n      console.log('Form submitted:', formData);\n      // 重置表单\n      setFormData({\n        name: '',\n        email: '',\n        password: '',\n        confirmPassword: '',\n        subscribe: false,\n        terms: false,\n      });\n    } else {\n      setErrors(newErrors);\n    }\n  };\n  \n  return (\n    \u003Cform onSubmit={handleSubmit} noValidate>\n      {submitted && (\n        \u003Cdiv className=\"form-success-message\" role=\"alert\">\n          注册成功！\n        \u003C/div>\n      )}\n      \n      \u003CFormInput\n        label=\"姓名\"\n        name=\"name\"\n        value={formData.name}\n        onChange={handleChange}\n        onBlur={handleBlur}\n        error={touched.name && errors.name}\n        helperText=\"请输入你的全名\"\n      />\n      \n      \u003CFormInput\n        label=\"邮箱\"\n        name=\"email\"\n        type=\"email\"\n        value={formData.email}\n        onChange={handleChange}\n        onBlur={handleBlur}\n        error={touched.email && errors.email}\n      />\n      \n      \u003CFormInput\n        label=\"密码\"\n        name=\"password\"\n        type=\"password\"\n        value={formData.password}\n        onChange={handleChange}\n        onBlur={handleBlur}\n        error={touched.password && errors.password}\n        helperText=\"至少 8 个字符\"\n      />\n      \n      \u003CFormInput\n        label=\"确认密码\"\n        name=\"confirmPassword\"\n        type=\"password\"\n        value={formData.confirmPassword}\n        onChange={handleChange}\n        onBlur={handleBlur}\n        error={touched.confirmPassword && errors.confirmPassword}\n      />\n      \n      \u003Cdiv className=\"form-group\">\n        \u003Clabel className=\"checkbox-label\">\n          \u003Cinput\n            type=\"checkbox\"\n            name=\"subscribe\"\n            checked={formData.subscribe}\n            onChange={handleChange}\n            className=\"checkbox-input\"\n          />\n          订阅我们的新闻通讯\n        \u003C/label>\n      \u003C/div>\n      \n      \u003Cdiv className=\"form-group\">\n        \u003Clabel className=\"checkbox-label\">\n          \u003Cinput\n            type=\"checkbox\"\n            name=\"terms\"\n            checked={formData.terms}\n            onChange={handleChange}\n            onBlur={handleBlur}\n            className=\"checkbox-input\"\n          />\n          我同意\n          \u003Ca href=\"/terms\" target=\"_blank\" rel=\"noopener noreferrer\">\n            服务条款\n          \u003C/a>\n          和\n          \u003Ca href=\"/privacy\" target=\"_blank\" rel=\"noopener noreferrer\">\n            隐私政策\n          \u003C/a>\n        \u003C/label>\n        {touched.terms && errors.terms && (\n          \u003Cp className=\"form-error\">{errors.terms}\u003C/p>\n        )}\n      \u003C/div>\n      \n      \u003Cbutton type=\"submit\" className=\"btn btn-primary btn-block\">\n        注册\n      \u003C/button>\n    \u003C/form>\n  );\n}\n",[1480],{"type":24,"tag":101,"props":1481,"children":1482},{"__ignoreMap":7},[1483],{"type":30,"value":1478},{"type":24,"tag":25,"props":1485,"children":1486},{"id":877},[1487],{"type":30,"value":877},{"type":24,"tag":32,"props":1489,"children":1490},{},[1491,1492,1496],{"type":30,"value":884},{"type":24,"tag":46,"props":1493,"children":1494},{},[1495],{"type":30,"value":889},{"type":30,"value":891},{"type":24,"tag":38,"props":1498,"children":1499},{},[1500,1505,1510,1515,1519],{"type":24,"tag":42,"props":1501,"children":1502},{},[1503],{"type":30,"value":1504},"使用正确的输入类型",{"type":24,"tag":42,"props":1506,"children":1507},{},[1508],{"type":30,"value":1509},"提供实时验证反馈",{"type":24,"tag":42,"props":1511,"children":1512},{},[1513],{"type":30,"value":1514},"清晰的标签和提示",{"type":24,"tag":42,"props":1516,"children":1517},{},[1518],{"type":30,"value":899},{"type":24,"tag":42,"props":1520,"children":1521},{},[1522],{"type":30,"value":925},{"type":24,"tag":32,"props":1524,"children":1525},{},[1526,1527,1531],{"type":30,"value":930},{"type":24,"tag":46,"props":1528,"children":1529},{},[1530],{"type":30,"value":935},{"type":30,"value":891},{"type":24,"tag":38,"props":1533,"children":1534},{},[1535,1540,1545,1550,1555],{"type":24,"tag":42,"props":1536,"children":1537},{},[1538],{"type":30,"value":1539},"隐藏标签",{"type":24,"tag":42,"props":1541,"children":1542},{},[1543],{"type":30,"value":1544},"过度使用占位符",{"type":24,"tag":42,"props":1546,"children":1547},{},[1548],{"type":30,"value":1549},"验证后立即提交",{"type":24,"tag":42,"props":1551,"children":1552},{},[1553],{"type":30,"value":1554},"忽视无障碍性",{"type":24,"tag":42,"props":1556,"children":1557},{},[1558],{"type":30,"value":1559},"复杂的验证规则",{"type":24,"tag":25,"props":1561,"children":1562},{"id":982},[1563],{"type":30,"value":982},{"type":24,"tag":38,"props":1565,"children":1567},{"className":1566},[988],[1568,1577,1586,1595,1604,1613],{"type":24,"tag":42,"props":1569,"children":1571},{"className":1570},[993],[1572,1575],{"type":24,"tag":996,"props":1573,"children":1574},{"disabled":998,"type":999},[],{"type":30,"value":1576}," 所有控件都可用键盘导航",{"type":24,"tag":42,"props":1578,"children":1580},{"className":1579},[993],[1581,1584],{"type":24,"tag":996,"props":1582,"children":1583},{"disabled":998,"type":999},[],{"type":30,"value":1585}," 标签与输入框关联",{"type":24,"tag":42,"props":1587,"children":1589},{"className":1588},[993],[1590,1593],{"type":24,"tag":996,"props":1591,"children":1592},{"disabled":998,"type":999},[],{"type":30,"value":1594}," 验证消息清晰",{"type":24,"tag":42,"props":1596,"children":1598},{"className":1597},[993],[1599,1602],{"type":24,"tag":996,"props":1600,"children":1601},{"disabled":998,"type":999},[],{"type":30,"value":1603}," 色彩对比度足够",{"type":24,"tag":42,"props":1605,"children":1607},{"className":1606},[993],[1608,1611],{"type":24,"tag":996,"props":1609,"children":1610},{"disabled":998,"type":999},[],{"type":30,"value":1612}," 屏幕阅读器兼容",{"type":24,"tag":42,"props":1614,"children":1616},{"className":1615},[993],[1617,1620],{"type":24,"tag":996,"props":1618,"children":1619},{"disabled":998,"type":999},[],{"type":30,"value":1621}," 移动设备测试",{"title":7,"searchDepth":661,"depth":661,"links":1623},[1624,1625,1629,1630,1631,1632,1633,1634,1635],{"id":1362,"depth":664,"text":1362},{"id":1384,"depth":664,"text":1384,"children":1626},[1627,1628],{"id":1389,"depth":661,"text":1389},{"id":1403,"depth":661,"text":1403},{"id":1368,"depth":664,"text":1368},{"id":1430,"depth":664,"text":1430},{"id":1444,"depth":664,"text":1444},{"id":1458,"depth":664,"text":1458},{"id":1472,"depth":664,"text":1472},{"id":877,"depth":664,"text":877},{"id":982,"depth":664,"text":982},"content:topics:design:form-controls-design.md","topics/design/form-controls-design.md","topics/design/form-controls-design",{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":8,"description":9,"date":10,"topic":5,"author":11,"tags":1640,"image":18,"featured":6,"readingTime":19,"body":1641,"_type":237,"_id":698,"_source":699,"_file":700,"_stem":701,"_extension":702},[13,14,15,16,17],{"type":21,"children":1642,"toc":2149},[1643,1647,1651,1686,1690,1694,1704,1773,1777,1784,1788,1795,1799,1803,1811,1815,1819,1827,1835,1839,1843,1851,1855,1863,1871,1879,1883,1897,1905,1912,1916,1920,1928,1932,1940,1944,1948,2017,2021,2028,2032,2040,2044,2048,2056,2060,2068,2072,2076,2084,2088,2092,2096,2104,2108,2112,2119,2127,2142],{"type":24,"tag":25,"props":1644,"children":1645},{"id":27},[1646],{"type":30,"value":27},{"type":24,"tag":32,"props":1648,"children":1649},{},[1650],{"type":30,"value":36},{"type":24,"tag":38,"props":1652,"children":1653},{},[1654,1662,1670,1678],{"type":24,"tag":42,"props":1655,"children":1656},{},[1657,1661],{"type":24,"tag":46,"props":1658,"children":1659},{},[1660],{"type":30,"value":50},{"type":30,"value":52},{"type":24,"tag":42,"props":1663,"children":1664},{},[1665,1669],{"type":24,"tag":46,"props":1666,"children":1667},{},[1668],{"type":30,"value":60},{"type":30,"value":62},{"type":24,"tag":42,"props":1671,"children":1672},{},[1673,1677],{"type":24,"tag":46,"props":1674,"children":1675},{},[1676],{"type":30,"value":70},{"type":30,"value":72},{"type":24,"tag":42,"props":1679,"children":1680},{},[1681,1685],{"type":24,"tag":46,"props":1682,"children":1683},{},[1684],{"type":30,"value":80},{"type":30,"value":82},{"type":24,"tag":25,"props":1687,"children":1688},{"id":85},[1689],{"type":30,"value":85},{"type":24,"tag":89,"props":1691,"children":1692},{"id":91},[1693],{"type":30,"value":94},{"type":24,"tag":32,"props":1695,"children":1696},{},[1697,1698,1703],{"type":30,"value":99},{"type":24,"tag":101,"props":1699,"children":1701},{"className":1700},[],[1702],{"type":30,"value":106},{"type":30,"value":108},{"type":24,"tag":110,"props":1705,"children":1706},{},[1707,1725],{"type":24,"tag":114,"props":1708,"children":1709},{},[1710],{"type":24,"tag":118,"props":1711,"children":1712},{},[1713,1717,1721],{"type":24,"tag":122,"props":1714,"children":1715},{},[1716],{"type":30,"value":126},{"type":24,"tag":122,"props":1718,"children":1719},{},[1720],{"type":30,"value":131},{"type":24,"tag":122,"props":1722,"children":1723},{},[1724],{"type":30,"value":136},{"type":24,"tag":138,"props":1726,"children":1727},{},[1728,1743,1758],{"type":24,"tag":118,"props":1729,"children":1730},{},[1731,1735,1739],{"type":24,"tag":145,"props":1732,"children":1733},{},[1734],{"type":30,"value":149},{"type":24,"tag":145,"props":1736,"children":1737},{},[1738],{"type":30,"value":154},{"type":24,"tag":145,"props":1740,"children":1741},{},[1742],{"type":30,"value":159},{"type":24,"tag":118,"props":1744,"children":1745},{},[1746,1750,1754],{"type":24,"tag":145,"props":1747,"children":1748},{},[1749],{"type":30,"value":167},{"type":24,"tag":145,"props":1751,"children":1752},{},[1753],{"type":30,"value":172},{"type":24,"tag":145,"props":1755,"children":1756},{},[1757],{"type":30,"value":177},{"type":24,"tag":118,"props":1759,"children":1760},{},[1761,1765,1769],{"type":24,"tag":145,"props":1762,"children":1763},{},[1764],{"type":30,"value":185},{"type":24,"tag":145,"props":1766,"children":1767},{},[1768],{"type":30,"value":190},{"type":24,"tag":145,"props":1770,"children":1771},{},[1772],{"type":30,"value":195},{"type":24,"tag":89,"props":1774,"children":1775},{"id":198},[1776],{"type":30,"value":198},{"type":24,"tag":202,"props":1778,"children":1779},{"code":204},[1780],{"type":24,"tag":101,"props":1781,"children":1782},{"__ignoreMap":7},[1783],{"type":30,"value":204},{"type":24,"tag":89,"props":1785,"children":1786},{"id":212},[1787],{"type":30,"value":212},{"type":24,"tag":202,"props":1789,"children":1790},{"code":217},[1791],{"type":24,"tag":101,"props":1792,"children":1793},{"__ignoreMap":7},[1794],{"type":30,"value":217},{"type":24,"tag":25,"props":1796,"children":1797},{"id":225},[1798],{"type":30,"value":225},{"type":24,"tag":89,"props":1800,"children":1801},{"id":230},[1802],{"type":30,"value":233},{"type":24,"tag":202,"props":1804,"children":1806},{"code":236,"language":237,"meta":7,"className":1805},[239],[1807],{"type":24,"tag":101,"props":1808,"children":1809},{"__ignoreMap":7},[1810],{"type":30,"value":236},{"type":24,"tag":89,"props":1812,"children":1813},{"id":247},[1814],{"type":30,"value":247},{"type":24,"tag":32,"props":1816,"children":1817},{},[1818],{"type":30,"value":254},{"type":24,"tag":202,"props":1820,"children":1822},{"code":257,"language":258,"meta":7,"className":1821},[260],[1823],{"type":24,"tag":101,"props":1824,"children":1825},{"__ignoreMap":7},[1826],{"type":30,"value":257},{"type":24,"tag":202,"props":1828,"children":1830},{"code":268,"language":269,"meta":7,"className":1829},[271],[1831],{"type":24,"tag":101,"props":1832,"children":1833},{"__ignoreMap":7},[1834],{"type":30,"value":268},{"type":24,"tag":25,"props":1836,"children":1837},{"id":279},[1838],{"type":30,"value":279},{"type":24,"tag":89,"props":1840,"children":1841},{"id":284},[1842],{"type":30,"value":284},{"type":24,"tag":202,"props":1844,"children":1846},{"code":289,"language":290,"meta":7,"className":1845},[292],[1847],{"type":24,"tag":101,"props":1848,"children":1849},{"__ignoreMap":7},[1850],{"type":30,"value":289},{"type":24,"tag":89,"props":1852,"children":1853},{"id":300},[1854],{"type":30,"value":300},{"type":24,"tag":202,"props":1856,"children":1858},{"code":305,"language":237,"meta":7,"className":1857},[239],[1859],{"type":24,"tag":101,"props":1860,"children":1861},{"__ignoreMap":7},[1862],{"type":30,"value":305},{"type":24,"tag":32,"props":1864,"children":1865},{},[1866,1870],{"type":24,"tag":46,"props":1867,"children":1868},{},[1869],{"type":30,"value":319},{"type":30,"value":321},{"type":24,"tag":202,"props":1872,"children":1874},{"code":324,"language":258,"meta":7,"className":1873},[260],[1875],{"type":24,"tag":101,"props":1876,"children":1877},{"__ignoreMap":7},[1878],{"type":30,"value":324},{"type":24,"tag":89,"props":1880,"children":1881},{"id":333},[1882],{"type":30,"value":336},{"type":24,"tag":32,"props":1884,"children":1885},{},[1886,1890,1891,1896],{"type":24,"tag":46,"props":1887,"children":1888},{},[1889],{"type":30,"value":344},{"type":30,"value":346},{"type":24,"tag":101,"props":1892,"children":1894},{"className":1893},[],[1895],{"type":30,"value":352},{"type":30,"value":354},{"type":24,"tag":202,"props":1898,"children":1900},{"code":357,"language":358,"meta":7,"className":1899},[360],[1901],{"type":24,"tag":101,"props":1902,"children":1903},{"__ignoreMap":7},[1904],{"type":30,"value":357},{"type":24,"tag":202,"props":1906,"children":1907},{"code":368},[1908],{"type":24,"tag":101,"props":1909,"children":1910},{"__ignoreMap":7},[1911],{"type":30,"value":368},{"type":24,"tag":25,"props":1913,"children":1914},{"id":376},[1915],{"type":30,"value":376},{"type":24,"tag":89,"props":1917,"children":1918},{"id":381},[1919],{"type":30,"value":381},{"type":24,"tag":202,"props":1921,"children":1923},{"code":386,"language":387,"meta":7,"className":1922},[389],[1924],{"type":24,"tag":101,"props":1925,"children":1926},{"__ignoreMap":7},[1927],{"type":30,"value":386},{"type":24,"tag":89,"props":1929,"children":1930},{"id":397},[1931],{"type":30,"value":397},{"type":24,"tag":202,"props":1933,"children":1935},{"code":402,"language":237,"meta":7,"className":1934},[239],[1936],{"type":24,"tag":101,"props":1937,"children":1938},{"__ignoreMap":7},[1939],{"type":30,"value":402},{"type":24,"tag":25,"props":1941,"children":1942},{"id":411},[1943],{"type":30,"value":411},{"type":24,"tag":89,"props":1945,"children":1946},{"id":416},[1947],{"type":30,"value":416},{"type":24,"tag":110,"props":1949,"children":1950},{},[1951,1969],{"type":24,"tag":114,"props":1952,"children":1953},{},[1954],{"type":24,"tag":118,"props":1955,"children":1956},{},[1957,1961,1965],{"type":24,"tag":122,"props":1958,"children":1959},{},[1960],{"type":30,"value":432},{"type":24,"tag":122,"props":1962,"children":1963},{},[1964],{"type":30,"value":437},{"type":24,"tag":122,"props":1966,"children":1967},{},[1968],{"type":30,"value":442},{"type":24,"tag":138,"props":1970,"children":1971},{},[1972,1987,2002],{"type":24,"tag":118,"props":1973,"children":1974},{},[1975,1979,1983],{"type":24,"tag":145,"props":1976,"children":1977},{},[1978],{"type":30,"value":453},{"type":24,"tag":145,"props":1980,"children":1981},{},[1982],{"type":30,"value":458},{"type":24,"tag":145,"props":1984,"children":1985},{},[1986],{"type":30,"value":463},{"type":24,"tag":118,"props":1988,"children":1989},{},[1990,1994,1998],{"type":24,"tag":145,"props":1991,"children":1992},{},[1993],{"type":30,"value":471},{"type":24,"tag":145,"props":1995,"children":1996},{},[1997],{"type":30,"value":476},{"type":24,"tag":145,"props":1999,"children":2000},{},[2001],{"type":30,"value":481},{"type":24,"tag":118,"props":2003,"children":2004},{},[2005,2009,2013],{"type":24,"tag":145,"props":2006,"children":2007},{},[2008],{"type":30,"value":489},{"type":24,"tag":145,"props":2010,"children":2011},{},[2012],{"type":30,"value":494},{"type":24,"tag":145,"props":2014,"children":2015},{},[2016],{"type":30,"value":499},{"type":24,"tag":89,"props":2018,"children":2019},{"id":502},[2020],{"type":30,"value":502},{"type":24,"tag":202,"props":2022,"children":2023},{"code":507},[2024],{"type":24,"tag":101,"props":2025,"children":2026},{"__ignoreMap":7},[2027],{"type":30,"value":507},{"type":24,"tag":89,"props":2029,"children":2030},{"id":515},[2031],{"type":30,"value":515},{"type":24,"tag":202,"props":2033,"children":2035},{"code":520,"language":258,"meta":7,"className":2034},[260],[2036],{"type":24,"tag":101,"props":2037,"children":2038},{"__ignoreMap":7},[2039],{"type":30,"value":520},{"type":24,"tag":25,"props":2041,"children":2042},{"id":529},[2043],{"type":30,"value":529},{"type":24,"tag":89,"props":2045,"children":2046},{"id":534},[2047],{"type":30,"value":537},{"type":24,"tag":202,"props":2049,"children":2051},{"code":540,"language":541,"meta":7,"className":2050},[543],[2052],{"type":24,"tag":101,"props":2053,"children":2054},{"__ignoreMap":7},[2055],{"type":30,"value":540},{"type":24,"tag":89,"props":2057,"children":2058},{"id":551},[2059],{"type":30,"value":551},{"type":24,"tag":202,"props":2061,"children":2063},{"code":556,"language":541,"meta":7,"className":2062},[543],[2064],{"type":24,"tag":101,"props":2065,"children":2066},{"__ignoreMap":7},[2067],{"type":30,"value":556},{"type":24,"tag":25,"props":2069,"children":2070},{"id":565},[2071],{"type":30,"value":565},{"type":24,"tag":89,"props":2073,"children":2074},{"id":570},[2075],{"type":30,"value":570},{"type":24,"tag":202,"props":2077,"children":2079},{"code":575,"language":237,"meta":7,"className":2078},[239],[2080],{"type":24,"tag":101,"props":2081,"children":2082},{"__ignoreMap":7},[2083],{"type":30,"value":575},{"type":24,"tag":89,"props":2085,"children":2086},{"id":584},[2087],{"type":30,"value":587},{"type":24,"tag":32,"props":2089,"children":2090},{},[2091],{"type":30,"value":592},{"type":24,"tag":25,"props":2093,"children":2094},{"id":595},[2095],{"type":30,"value":595},{"type":24,"tag":202,"props":2097,"children":2099},{"code":600,"language":258,"meta":7,"className":2098},[260],[2100],{"type":24,"tag":101,"props":2101,"children":2102},{"__ignoreMap":7},[2103],{"type":30,"value":600},{"type":24,"tag":25,"props":2105,"children":2106},{"id":609},[2107],{"type":30,"value":609},{"type":24,"tag":32,"props":2109,"children":2110},{},[2111],{"type":30,"value":616},{"type":24,"tag":202,"props":2113,"children":2114},{"code":619},[2115],{"type":24,"tag":101,"props":2116,"children":2117},{"__ignoreMap":7},[2118],{"type":30,"value":619},{"type":24,"tag":32,"props":2120,"children":2121},{},[2122,2126],{"type":24,"tag":46,"props":2123,"children":2124},{},[2125],{"type":30,"value":632},{"type":30,"value":321},{"type":24,"tag":38,"props":2128,"children":2129},{},[2130,2134,2138],{"type":24,"tag":42,"props":2131,"children":2132},{},[2133],{"type":30,"value":641},{"type":24,"tag":42,"props":2135,"children":2136},{},[2137],{"type":30,"value":646},{"type":24,"tag":42,"props":2139,"children":2140},{},[2141],{"type":30,"value":651},{"type":24,"tag":202,"props":2143,"children":2144},{"code":654},[2145],{"type":24,"tag":101,"props":2146,"children":2147},{"__ignoreMap":7},[2148],{"type":30,"value":654},{"title":7,"searchDepth":661,"depth":661,"links":2150},[2151,2152,2157,2161,2166,2170,2175,2179,2183,2184],{"id":27,"depth":664,"text":27},{"id":85,"depth":664,"text":85,"children":2153},[2154,2155,2156],{"id":91,"depth":661,"text":94},{"id":198,"depth":661,"text":198},{"id":212,"depth":661,"text":212},{"id":225,"depth":664,"text":225,"children":2158},[2159,2160],{"id":230,"depth":661,"text":233},{"id":247,"depth":661,"text":247},{"id":279,"depth":664,"text":279,"children":2162},[2163,2164,2165],{"id":284,"depth":661,"text":284},{"id":300,"depth":661,"text":300},{"id":333,"depth":661,"text":336},{"id":376,"depth":664,"text":376,"children":2167},[2168,2169],{"id":381,"depth":661,"text":381},{"id":397,"depth":661,"text":397},{"id":411,"depth":664,"text":411,"children":2171},[2172,2173,2174],{"id":416,"depth":661,"text":416},{"id":502,"depth":661,"text":502},{"id":515,"depth":661,"text":515},{"id":529,"depth":664,"text":529,"children":2176},[2177,2178],{"id":534,"depth":661,"text":537},{"id":551,"depth":661,"text":551},{"id":565,"depth":664,"text":565,"children":2180},[2181,2182],{"id":570,"depth":661,"text":570},{"id":584,"depth":661,"text":587},{"id":595,"depth":664,"text":595},{"id":609,"depth":664,"text":609},1778574590906]