[{"data":1,"prerenderedAt":1582},["ShallowReactive",2],{"article-/topics/design/design-system-documentation-best-practices":3,"related-design":370,"content-query-htfc7VmuiU":1312},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":8,"description":9,"date":10,"topic":5,"author":11,"tags":12,"image":18,"imageQuery":19,"pexelsPhotoId":20,"pexelsUrl":21,"featured":6,"readingTime":22,"body":23,"_type":364,"_id":365,"_source":366,"_file":367,"_stem":368,"_extension":369},"/topics/design/design-system-documentation-best-practices","design",false,"","设计系统文档化最佳实践：让规范真正被团队使用而不是被收藏","设计系统文档真正难的不是写出来，而是能否被设计、开发和产品持续使用。本文从结构组织、示例方式和维护机制出发，讲清设计系统文档化的最佳实践。","2026-04-25","HTMLPAGE 团队",[13,14,15,16,17],"Design System","Documentation","Collaboration","Component Library","Design Ops","/images/topics/design/design-system-documentation-best-practices.jpg","design system documentation interface on laptop",546819,"https://www.pexels.com/photo/close-up-photo-of-programming-of-codes-546819/",14,{"type":24,"children":25,"toc":353},"root",[26,34,54,59,64,71,76,94,99,105,110,115,138,143,149,154,159,182,187,192,197,202,225,230,236,241,246,269,274,279,307,312,317,322],{"type":27,"tag":28,"props":29,"children":30},"element","p",{},[31],{"type":32,"value":33},"text","很多团队的设计系统文档都存在同一个问题：",{"type":27,"tag":35,"props":36,"children":37},"ul",{},[38,44,49],{"type":27,"tag":39,"props":40,"children":41},"li",{},[42],{"type":32,"value":43},"写过",{"type":27,"tag":39,"props":45,"children":46},{},[47],{"type":32,"value":48},"放着",{"type":27,"tag":39,"props":50,"children":51},{},[52],{"type":32,"value":53},"但没人真正使用",{"type":27,"tag":28,"props":55,"children":56},{},[57],{"type":32,"value":58},"这并不一定是因为大家不重视文档，而是因为文档没有真正服务到工作流。",{"type":27,"tag":28,"props":60,"children":61},{},[62],{"type":32,"value":63},"设计系统文档化最佳实践真正要解决的，是让规范从“资料库”变成“协作入口”。",{"type":27,"tag":65,"props":66,"children":68},"h2",{"id":67},"文档先解决的是团队怎么判断不是信息怎么堆",[69],{"type":32,"value":70},"文档先解决的是“团队怎么判断”，不是“信息怎么堆”",{"type":27,"tag":28,"props":72,"children":73},{},[74],{"type":32,"value":75},"文档最常见的失败方式，是把大量规则堆进去，但团队看完仍然不知道：",{"type":27,"tag":35,"props":77,"children":78},{},[79,84,89],{"type":27,"tag":39,"props":80,"children":81},{},[82],{"type":32,"value":83},"什么时候该用哪个组件",{"type":27,"tag":39,"props":85,"children":86},{},[87],{"type":32,"value":88},"哪些是推荐方案",{"type":27,"tag":39,"props":90,"children":91},{},[92],{"type":32,"value":93},"出现边界情况该怎么判断",{"type":27,"tag":28,"props":95,"children":96},{},[97],{"type":32,"value":98},"所以好的文档更像判断系统，而不只是信息集合。",{"type":27,"tag":65,"props":100,"children":102},{"id":101},"结构组织要围绕任务而不是围绕作者思路",[103],{"type":32,"value":104},"结构组织要围绕任务，而不是围绕作者思路",{"type":27,"tag":28,"props":106,"children":107},{},[108],{"type":32,"value":109},"很多文档结构从作者角度看很完整，但从使用者角度并不高效。",{"type":27,"tag":28,"props":111,"children":112},{},[113],{"type":32,"value":114},"更可用的组织方式通常围绕：",{"type":27,"tag":35,"props":116,"children":117},{},[118,123,128,133],{"type":27,"tag":39,"props":119,"children":120},{},[121],{"type":32,"value":122},"组件怎么选",{"type":27,"tag":39,"props":124,"children":125},{},[126],{"type":32,"value":127},"组件怎么用",{"type":27,"tag":39,"props":129,"children":130},{},[131],{"type":32,"value":132},"什么时候不要这样用",{"type":27,"tag":39,"props":134,"children":135},{},[136],{"type":32,"value":137},"设计和开发各自要看什么",{"type":27,"tag":28,"props":139,"children":140},{},[141],{"type":32,"value":142},"用户进入文档时，首先关心的通常不是背景介绍，而是当前任务怎么做。",{"type":27,"tag":65,"props":144,"children":146},{"id":145},"示例必须覆盖正常态-边界态",[147],{"type":32,"value":148},"示例必须覆盖“正常态 + 边界态”",{"type":27,"tag":28,"props":150,"children":151},{},[152],{"type":32,"value":153},"设计系统文档如果只有最理想的示例，实际帮助会很有限。",{"type":27,"tag":28,"props":155,"children":156},{},[157],{"type":32,"value":158},"真正高价值的示例往往包括：",{"type":27,"tag":35,"props":160,"children":161},{},[162,167,172,177],{"type":27,"tag":39,"props":163,"children":164},{},[165],{"type":32,"value":166},"基础使用",{"type":27,"tag":39,"props":168,"children":169},{},[170],{"type":32,"value":171},"推荐模式",{"type":27,"tag":39,"props":173,"children":174},{},[175],{"type":32,"value":176},"反例或禁用方式",{"type":27,"tag":39,"props":178,"children":179},{},[180],{"type":32,"value":181},"异常态和特殊场景",{"type":27,"tag":28,"props":183,"children":184},{},[185],{"type":32,"value":186},"这样团队在真实项目中才更容易做正确判断。",{"type":27,"tag":65,"props":188,"children":190},{"id":189},"文档必须和真实实现保持联动",[191],{"type":32,"value":189},{"type":27,"tag":28,"props":193,"children":194},{},[195],{"type":32,"value":196},"设计系统文档一旦和组件实现脱节，很快就会失去公信力。",{"type":27,"tag":28,"props":198,"children":199},{},[200],{"type":32,"value":201},"所以文档化最佳实践通常不是单独写文档，而是让文档与：",{"type":27,"tag":35,"props":203,"children":204},{},[205,210,215,220],{"type":27,"tag":39,"props":206,"children":207},{},[208],{"type":32,"value":209},"组件状态",{"type":27,"tag":39,"props":211,"children":212},{},[213],{"type":32,"value":214},"代码示例",{"type":27,"tag":39,"props":216,"children":217},{},[218],{"type":32,"value":219},"设计资产",{"type":27,"tag":39,"props":221,"children":222},{},[223],{"type":32,"value":224},"更新记录",{"type":27,"tag":28,"props":226,"children":227},{},[228],{"type":32,"value":229},"保持联动。",{"type":27,"tag":65,"props":231,"children":233},{"id":232},"一个常见失败案例文档很多但团队沟通成本并没有下降",[234],{"type":32,"value":235},"一个常见失败案例：文档很多，但团队沟通成本并没有下降",{"type":27,"tag":28,"props":237,"children":238},{},[239],{"type":32,"value":240},"这类情况通常说明文档没有嵌入工作流。",{"type":27,"tag":28,"props":242,"children":243},{},[244],{"type":32,"value":245},"问题往往是：",{"type":27,"tag":35,"props":247,"children":248},{},[249,254,259,264],{"type":27,"tag":39,"props":250,"children":251},{},[252],{"type":32,"value":253},"结构不围绕任务",{"type":27,"tag":39,"props":255,"children":256},{},[257],{"type":32,"value":258},"示例不覆盖真实边界",{"type":27,"tag":39,"props":260,"children":261},{},[262],{"type":32,"value":263},"文档和组件现状不同步",{"type":27,"tag":39,"props":265,"children":266},{},[267],{"type":32,"value":268},"没有人维护更新",{"type":27,"tag":28,"props":270,"children":271},{},[272],{"type":32,"value":273},"结果就是文档在，但大家仍然只能口头确认。",{"type":27,"tag":65,"props":275,"children":277},{"id":276},"一份可直接复用的检查清单",[278],{"type":32,"value":276},{"type":27,"tag":35,"props":280,"children":281},{},[282,287,292,297,302],{"type":27,"tag":39,"props":283,"children":284},{},[285],{"type":32,"value":286},"文档是否围绕团队判断与任务使用来组织",{"type":27,"tag":39,"props":288,"children":289},{},[290],{"type":32,"value":291},"结构是否优先服务组件选择、使用和边界决策",{"type":27,"tag":39,"props":293,"children":294},{},[295],{"type":32,"value":296},"示例是否覆盖推荐模式、边界态和反例",{"type":27,"tag":39,"props":298,"children":299},{},[300],{"type":32,"value":301},"文档是否与组件实现、设计资产和更新记录联动",{"type":27,"tag":39,"props":303,"children":304},{},[305],{"type":32,"value":306},"文档维护是否进入了正式流程而不是临时补充",{"type":27,"tag":65,"props":308,"children":310},{"id":309},"总结",[311],{"type":32,"value":309},{"type":27,"tag":28,"props":313,"children":314},{},[315],{"type":32,"value":316},"设计系统文档化真正的目标，不是积累更多页面，而是让团队在协作中更少靠记忆和口头解释。只要先把结构、示例和联动机制设计好，文档才会真正成为系统的一部分。",{"type":27,"tag":28,"props":318,"children":319},{},[320],{"type":32,"value":321},"进一步阅读：",{"type":27,"tag":35,"props":323,"children":324},{},[325,335,344],{"type":27,"tag":39,"props":326,"children":327},{},[328],{"type":27,"tag":329,"props":330,"children":332},"a",{"href":331},"/topics/design/storybook-7-complete-practice",[333],{"type":32,"value":334},"Storybook 7 完整实践",{"type":27,"tag":39,"props":336,"children":337},{},[338],{"type":27,"tag":329,"props":339,"children":341},{"href":340},"/topics/design/design-development-collaboration-workflow",[342],{"type":32,"value":343},"设计与开发协作流程",{"type":27,"tag":39,"props":345,"children":346},{},[347],{"type":27,"tag":329,"props":348,"children":350},{"href":349},"/topics/design/design-review-quality-control-guide",[351],{"type":32,"value":352},"设计走查与质量管控",{"title":7,"searchDepth":354,"depth":354,"links":355},3,[356,358,359,360,361,362,363],{"id":67,"depth":357,"text":70},2,{"id":101,"depth":357,"text":104},{"id":145,"depth":357,"text":148},{"id":189,"depth":357,"text":189},{"id":232,"depth":357,"text":235},{"id":276,"depth":357,"text":276},{"id":309,"depth":357,"text":309},"markdown","content:topics:design:design-system-documentation-best-practices.md","content","topics/design/design-system-documentation-best-practices.md","topics/design/design-system-documentation-best-practices","md",[371,731,1033],{"_path":372,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":373,"description":374,"keywords":375,"image":381,"author":11,"date":382,"readingTime":383,"topic":5,"body":384,"_type":364,"_id":728,"_source":366,"_file":729,"_stem":730,"_extension":369},"/topics/design/button-component-design","按钮组件设计详解","学习按钮样式、交互状态、无障碍性和最佳实践",[376,377,378,379,380],"按钮设计","Button Component","交互状态","UI 组件","用户体验","/images/topics/button-design.jpg","2025-12-08",18,{"type":24,"children":385,"toc":710},[386,390,395,400,407,420,426,435,441,450,454,460,471,477,486,492,501,506,515,520,531,536,545,550,563,597,608,651,656],{"type":27,"tag":65,"props":387,"children":388},{"id":373},[389],{"type":32,"value":373},{"type":27,"tag":28,"props":391,"children":392},{},[393],{"type":32,"value":394},"按钮是 UI 中最重要的交互元素。优秀的按钮设计能够指导用户行为。",{"type":27,"tag":65,"props":396,"children":398},{"id":397},"按钮类型",[399],{"type":32,"value":397},{"type":27,"tag":401,"props":402,"children":404},"h3",{"id":403},"primary-button主按钮",[405],{"type":32,"value":406},"Primary Button（主按钮）",{"type":27,"tag":408,"props":409,"children":414},"pre",{"className":410,"code":412,"language":413,"meta":7},[411],"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",[415],{"type":27,"tag":416,"props":417,"children":418},"code",{"__ignoreMap":7},[419],{"type":32,"value":412},{"type":27,"tag":401,"props":421,"children":423},{"id":422},"secondary-button次按钮",[424],{"type":32,"value":425},"Secondary Button（次按钮）",{"type":27,"tag":408,"props":427,"children":430},{"className":428,"code":429,"language":413,"meta":7},[411],".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",[431],{"type":27,"tag":416,"props":432,"children":433},{"__ignoreMap":7},[434],{"type":32,"value":429},{"type":27,"tag":401,"props":436,"children":438},{"id":437},"danger-button危险按钮",[439],{"type":32,"value":440},"Danger Button（危险按钮）",{"type":27,"tag":408,"props":442,"children":445},{"className":443,"code":444,"language":413,"meta":7},[411],".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",[446],{"type":27,"tag":416,"props":447,"children":448},{"__ignoreMap":7},[449],{"type":32,"value":444},{"type":27,"tag":65,"props":451,"children":452},{"id":378},[453],{"type":32,"value":378},{"type":27,"tag":401,"props":455,"children":457},{"id":456},"loading-状态",[458],{"type":32,"value":459},"Loading 状态",{"type":27,"tag":408,"props":461,"children":466},{"className":462,"code":464,"language":465,"meta":7},[463],"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",[467],{"type":27,"tag":416,"props":468,"children":469},{"__ignoreMap":7},[470],{"type":32,"value":464},{"type":27,"tag":401,"props":472,"children":474},{"id":473},"disabled-状态",[475],{"type":32,"value":476},"Disabled 状态",{"type":27,"tag":408,"props":478,"children":481},{"className":479,"code":480,"language":413,"meta":7},[411],".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",[482],{"type":27,"tag":416,"props":483,"children":484},{"__ignoreMap":7},[485],{"type":32,"value":480},{"type":27,"tag":401,"props":487,"children":489},{"id":488},"focus-状态",[490],{"type":32,"value":491},"Focus 状态",{"type":27,"tag":408,"props":493,"children":496},{"className":494,"code":495,"language":413,"meta":7},[411],".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",[497],{"type":27,"tag":416,"props":498,"children":499},{"__ignoreMap":7},[500],{"type":32,"value":495},{"type":27,"tag":65,"props":502,"children":504},{"id":503},"按钮大小",[505],{"type":32,"value":503},{"type":27,"tag":408,"props":507,"children":510},{"className":508,"code":509,"language":413,"meta":7},[411],"/* 小按钮 */\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",[511],{"type":27,"tag":416,"props":512,"children":513},{"__ignoreMap":7},[514],{"type":32,"value":509},{"type":27,"tag":65,"props":516,"children":518},{"id":517},"无障碍性",[519],{"type":32,"value":517},{"type":27,"tag":408,"props":521,"children":526},{"className":522,"code":524,"language":525,"meta":7},[523],"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",[527],{"type":27,"tag":416,"props":528,"children":529},{"__ignoreMap":7},[530],{"type":32,"value":524},{"type":27,"tag":65,"props":532,"children":534},{"id":533},"完整组件示例",[535],{"type":32,"value":533},{"type":27,"tag":408,"props":537,"children":540},{"className":538,"code":539,"language":465,"meta":7},[463],"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",[541],{"type":27,"tag":416,"props":542,"children":543},{"__ignoreMap":7},[544],{"type":32,"value":539},{"type":27,"tag":65,"props":546,"children":548},{"id":547},"最佳实践",[549],{"type":32,"value":547},{"type":27,"tag":28,"props":551,"children":552},{},[553,555,561],{"type":32,"value":554},"✅ ",{"type":27,"tag":556,"props":557,"children":558},"strong",{},[559],{"type":32,"value":560},"应该做的事",{"type":32,"value":562},":",{"type":27,"tag":35,"props":564,"children":565},{},[566,571,576,587,592],{"type":27,"tag":39,"props":567,"children":568},{},[569],{"type":32,"value":570},"最小触摸目标 44x44px",{"type":27,"tag":39,"props":572,"children":573},{},[574],{"type":32,"value":575},"清晰的视觉反馈",{"type":27,"tag":39,"props":577,"children":578},{},[579,581],{"type":32,"value":580},"使用语义 HTML ",{"type":27,"tag":416,"props":582,"children":584},{"className":583},[],[585],{"type":32,"value":586},"\u003Cbutton>",{"type":27,"tag":39,"props":588,"children":589},{},[590],{"type":32,"value":591},"提供加载状态反馈",{"type":27,"tag":39,"props":593,"children":594},{},[595],{"type":32,"value":596},"支持键盘导航",{"type":27,"tag":28,"props":598,"children":599},{},[600,602,607],{"type":32,"value":601},"❌ ",{"type":27,"tag":556,"props":603,"children":604},{},[605],{"type":32,"value":606},"不应该做的事",{"type":32,"value":562},{"type":27,"tag":35,"props":609,"children":610},{},[611,624,629,634,639],{"type":27,"tag":39,"props":612,"children":613},{},[614,616,622],{"type":32,"value":615},"使用 ",{"type":27,"tag":416,"props":617,"children":619},{"className":618},[],[620],{"type":32,"value":621},"\u003Cdiv>",{"type":32,"value":623}," 模拟按钮",{"type":27,"tag":39,"props":625,"children":626},{},[627],{"type":32,"value":628},"隐藏焦点指示器",{"type":27,"tag":39,"props":630,"children":631},{},[632],{"type":32,"value":633},"过多的按钮样式",{"type":27,"tag":39,"props":635,"children":636},{},[637],{"type":32,"value":638},"忽视禁用状态",{"type":27,"tag":39,"props":640,"children":641},{},[642,643,649],{"type":32,"value":615},{"type":27,"tag":416,"props":644,"children":646},{"className":645},[],[647],{"type":32,"value":648},"\u003Ca>",{"type":32,"value":650}," 代替按钮",{"type":27,"tag":65,"props":652,"children":654},{"id":653},"测试清单",[655],{"type":32,"value":653},{"type":27,"tag":35,"props":657,"children":660},{"className":658},[659],"contains-task-list",[661,674,683,692,701],{"type":27,"tag":39,"props":662,"children":665},{"className":663},[664],"task-list-item",[666,672],{"type":27,"tag":667,"props":668,"children":671},"input",{"disabled":669,"type":670},true,"checkbox",[],{"type":32,"value":673}," 在各种浏览器中测试",{"type":27,"tag":39,"props":675,"children":677},{"className":676},[664],[678,681],{"type":27,"tag":667,"props":679,"children":680},{"disabled":669,"type":670},[],{"type":32,"value":682}," 验证键盘导航",{"type":27,"tag":39,"props":684,"children":686},{"className":685},[664],[687,690],{"type":27,"tag":667,"props":688,"children":689},{"disabled":669,"type":670},[],{"type":32,"value":691}," 检查色彩对比度",{"type":27,"tag":39,"props":693,"children":695},{"className":694},[664],[696,699],{"type":27,"tag":667,"props":697,"children":698},{"disabled":669,"type":670},[],{"type":32,"value":700}," 测试触摸设备",{"type":27,"tag":39,"props":702,"children":704},{"className":703},[664],[705,708],{"type":27,"tag":667,"props":706,"children":707},{"disabled":669,"type":670},[],{"type":32,"value":709}," 屏幕阅读器兼容性",{"title":7,"searchDepth":354,"depth":354,"links":711},[712,713,718,723,724,725,726,727],{"id":373,"depth":357,"text":373},{"id":397,"depth":357,"text":397,"children":714},[715,716,717],{"id":403,"depth":354,"text":406},{"id":422,"depth":354,"text":425},{"id":437,"depth":354,"text":440},{"id":378,"depth":357,"text":378,"children":719},[720,721,722],{"id":456,"depth":354,"text":459},{"id":473,"depth":354,"text":476},{"id":488,"depth":354,"text":491},{"id":503,"depth":357,"text":503},{"id":517,"depth":357,"text":517},{"id":533,"depth":357,"text":533},{"id":547,"depth":357,"text":547},{"id":653,"depth":357,"text":653},"content:topics:design:button-component-design.md","topics/design/button-component-design.md","topics/design/button-component-design",{"_path":732,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":733,"description":734,"keywords":735,"image":740,"author":11,"date":382,"readingTime":741,"topic":5,"body":742,"_type":364,"_id":1030,"_source":366,"_file":1031,"_stem":1032,"_extension":369},"/topics/design/dark-mode-design","暗黑模式设计完整方案","学习暗黑模式实现、色彩方案、对比度管理和最佳实践",[736,737,738,739,380],"暗黑模式","Dark Mode","色彩系统","CSS 变量","/images/topics/dark-mode-design.jpg",20,{"type":24,"children":743,"toc":1013},[744,748,753,758,764,773,779,788,793,799,808,814,825,831,840,845,854,859,868,873,882,886,895,923,932,960,964],{"type":27,"tag":65,"props":745,"children":746},{"id":733},[747],{"type":32,"value":733},{"type":27,"tag":28,"props":749,"children":750},{},[751],{"type":32,"value":752},"暗黑模式已成为现代应用的标准功能。它能够减少眼睛疲劳、节省电池、改善用户体验。",{"type":27,"tag":65,"props":754,"children":756},{"id":755},"核心色彩系统",[757],{"type":32,"value":755},{"type":27,"tag":401,"props":759,"children":761},{"id":760},"light-mode-配色",[762],{"type":32,"value":763},"Light Mode 配色",{"type":27,"tag":408,"props":765,"children":768},{"className":766,"code":767,"language":413,"meta":7},[411],":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",[769],{"type":27,"tag":416,"props":770,"children":771},{"__ignoreMap":7},[772],{"type":32,"value":767},{"type":27,"tag":401,"props":774,"children":776},{"id":775},"dark-mode-配色",[777],{"type":32,"value":778},"Dark Mode 配色",{"type":27,"tag":408,"props":780,"children":783},{"className":781,"code":782,"language":413,"meta":7},[411],"@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",[784],{"type":27,"tag":416,"props":785,"children":786},{"__ignoreMap":7},[787],{"type":32,"value":782},{"type":27,"tag":65,"props":789,"children":791},{"id":790},"实现方案",[792],{"type":32,"value":790},{"type":27,"tag":401,"props":794,"children":796},{"id":795},"方案-1prefers-color-scheme",[797],{"type":32,"value":798},"方案 1：prefers-color-scheme",{"type":27,"tag":408,"props":800,"children":803},{"className":801,"code":802,"language":413,"meta":7},[411],"/* 自动跟随系统设置 */\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",[804],{"type":27,"tag":416,"props":805,"children":806},{"__ignoreMap":7},[807],{"type":32,"value":802},{"type":27,"tag":401,"props":809,"children":811},{"id":810},"方案-2javascript-切换",[812],{"type":32,"value":813},"方案 2：JavaScript 切换",{"type":27,"tag":408,"props":815,"children":820},{"className":816,"code":818,"language":819,"meta":7},[817],"language-javascript","// 检测和切换暗黑模式\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","javascript",[821],{"type":27,"tag":416,"props":822,"children":823},{"__ignoreMap":7},[824],{"type":32,"value":818},{"type":27,"tag":401,"props":826,"children":828},{"id":827},"方案-3css-variables-javascript",[829],{"type":32,"value":830},"方案 3：CSS Variables + JavaScript",{"type":27,"tag":408,"props":832,"children":835},{"className":833,"code":834,"language":819,"meta":7},[817],"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",[836],{"type":27,"tag":416,"props":837,"children":838},{"__ignoreMap":7},[839],{"type":32,"value":834},{"type":27,"tag":65,"props":841,"children":843},{"id":842},"对比度管理",[844],{"type":32,"value":842},{"type":27,"tag":408,"props":846,"children":849},{"className":847,"code":848,"language":413,"meta":7},[411],"/* 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",[850],{"type":27,"tag":416,"props":851,"children":852},{"__ignoreMap":7},[853],{"type":32,"value":848},{"type":27,"tag":65,"props":855,"children":857},{"id":856},"图片和图表处理",[858],{"type":32,"value":856},{"type":27,"tag":408,"props":860,"children":863},{"className":861,"code":862,"language":525,"meta":7},[523],"\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",[864],{"type":27,"tag":416,"props":865,"children":866},{"__ignoreMap":7},[867],{"type":32,"value":862},{"type":27,"tag":65,"props":869,"children":871},{"id":870},"完整示例",[872],{"type":32,"value":870},{"type":27,"tag":408,"props":874,"children":877},{"className":875,"code":876,"language":465,"meta":7},[463],"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",[878],{"type":27,"tag":416,"props":879,"children":880},{"__ignoreMap":7},[881],{"type":32,"value":876},{"type":27,"tag":65,"props":883,"children":884},{"id":547},[885],{"type":32,"value":547},{"type":27,"tag":28,"props":887,"children":888},{},[889,890,894],{"type":32,"value":554},{"type":27,"tag":556,"props":891,"children":892},{},[893],{"type":32,"value":560},{"type":32,"value":562},{"type":27,"tag":35,"props":896,"children":897},{},[898,903,908,913,918],{"type":27,"tag":39,"props":899,"children":900},{},[901],{"type":32,"value":902},"支持系统偏好",{"type":27,"tag":39,"props":904,"children":905},{},[906],{"type":32,"value":907},"提供手动切换选项",{"type":27,"tag":39,"props":909,"children":910},{},[911],{"type":32,"value":912},"确保足够的对比度",{"type":27,"tag":39,"props":914,"children":915},{},[916],{"type":32,"value":917},"优化图片和图表",{"type":27,"tag":39,"props":919,"children":920},{},[921],{"type":32,"value":922},"防止加载闪烁",{"type":27,"tag":28,"props":924,"children":925},{},[926,927,931],{"type":32,"value":601},{"type":27,"tag":556,"props":928,"children":929},{},[930],{"type":32,"value":606},{"type":32,"value":562},{"type":27,"tag":35,"props":933,"children":934},{},[935,940,945,950,955],{"type":27,"tag":39,"props":936,"children":937},{},[938],{"type":32,"value":939},"强制单一模式",{"type":27,"tag":39,"props":941,"children":942},{},[943],{"type":32,"value":944},"忽视性能影响",{"type":27,"tag":39,"props":946,"children":947},{},[948],{"type":32,"value":949},"使用相同的颜色",{"type":27,"tag":39,"props":951,"children":952},{},[953],{"type":32,"value":954},"忘记保存用户偏好",{"type":27,"tag":39,"props":956,"children":957},{},[958],{"type":32,"value":959},"过度使用深色背景",{"type":27,"tag":65,"props":961,"children":962},{"id":653},[963],{"type":32,"value":653},{"type":27,"tag":35,"props":965,"children":967},{"className":966},[659],[968,977,986,995,1004],{"type":27,"tag":39,"props":969,"children":971},{"className":970},[664],[972,975],{"type":27,"tag":667,"props":973,"children":974},{"disabled":669,"type":670},[],{"type":32,"value":976}," 在浅色和深色模式下测试所有页面",{"type":27,"tag":39,"props":978,"children":980},{"className":979},[664],[981,984],{"type":27,"tag":667,"props":982,"children":983},{"disabled":669,"type":670},[],{"type":32,"value":985}," 检查颜色对比度符合 WCAG 标准",{"type":27,"tag":39,"props":987,"children":989},{"className":988},[664],[990,993],{"type":27,"tag":667,"props":991,"children":992},{"disabled":669,"type":670},[],{"type":32,"value":994}," 验证图片和图表在两种模式下清晰",{"type":27,"tag":39,"props":996,"children":998},{"className":997},[664],[999,1002],{"type":27,"tag":667,"props":1000,"children":1001},{"disabled":669,"type":670},[],{"type":32,"value":1003}," 测试主题切换的平滑性",{"type":27,"tag":39,"props":1005,"children":1007},{"className":1006},[664],[1008,1011],{"type":27,"tag":667,"props":1009,"children":1010},{"disabled":669,"type":670},[],{"type":32,"value":1012}," 检查用户偏好是否被保存",{"title":7,"searchDepth":354,"depth":354,"links":1014},[1015,1016,1020,1025,1026,1027,1028,1029],{"id":733,"depth":357,"text":733},{"id":755,"depth":357,"text":755,"children":1017},[1018,1019],{"id":760,"depth":354,"text":763},{"id":775,"depth":354,"text":778},{"id":790,"depth":357,"text":790,"children":1021},[1022,1023,1024],{"id":795,"depth":354,"text":798},{"id":810,"depth":354,"text":813},{"id":827,"depth":354,"text":830},{"id":842,"depth":357,"text":842},{"id":856,"depth":357,"text":856},{"id":870,"depth":357,"text":870},{"id":547,"depth":357,"text":547},{"id":653,"depth":357,"text":653},"content:topics:design:dark-mode-design.md","topics/design/dark-mode-design.md","topics/design/dark-mode-design",{"_path":1034,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":1035,"description":1036,"keywords":1037,"image":1042,"author":1043,"date":382,"readingTime":741,"topic":5,"body":1044,"_type":364,"_id":1309,"_source":366,"_file":1310,"_stem":1311,"_extension":369},"/topics/design/form-controls-design","表单控件设计规范","学习输入框、选择框、复选框等表单控件的设计和实现",[1038,1039,1040,1041,380],"表单设计","Form Controls","输入框","验证反馈","/images/topics/form-controls-design.jpg","AI Content Team",{"type":24,"children":1045,"toc":1295},[1046,1050,1055,1060,1065,1074,1079,1088,1092,1101,1106,1115,1120,1129,1134,1143,1148,1157,1161,1170,1196,1205,1233,1237],{"type":27,"tag":65,"props":1047,"children":1048},{"id":1035},[1049],{"type":32,"value":1035},{"type":27,"tag":28,"props":1051,"children":1052},{},[1053],{"type":32,"value":1054},"优秀的表单设计能够提高用户完成率和满意度。",{"type":27,"tag":65,"props":1056,"children":1058},{"id":1057},"输入框设计",[1059],{"type":32,"value":1057},{"type":27,"tag":401,"props":1061,"children":1063},{"id":1062},"基础文本输入",[1064],{"type":32,"value":1062},{"type":27,"tag":408,"props":1066,"children":1069},{"className":1067,"code":1068,"language":413,"meta":7},[411],".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",[1070],{"type":27,"tag":416,"props":1071,"children":1072},{"__ignoreMap":7},[1073],{"type":32,"value":1068},{"type":27,"tag":401,"props":1075,"children":1077},{"id":1076},"标签和提示",[1078],{"type":32,"value":1076},{"type":27,"tag":408,"props":1080,"children":1083},{"className":1081,"code":1082,"language":525,"meta":7},[523],"\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",[1084],{"type":27,"tag":416,"props":1085,"children":1086},{"__ignoreMap":7},[1087],{"type":32,"value":1082},{"type":27,"tag":65,"props":1089,"children":1090},{"id":1041},[1091],{"type":32,"value":1041},{"type":27,"tag":408,"props":1093,"children":1096},{"className":1094,"code":1095,"language":465,"meta":7},[463],"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",[1097],{"type":27,"tag":416,"props":1098,"children":1099},{"__ignoreMap":7},[1100],{"type":32,"value":1095},{"type":27,"tag":65,"props":1102,"children":1104},{"id":1103},"选择框设计",[1105],{"type":32,"value":1103},{"type":27,"tag":408,"props":1107,"children":1110},{"className":1108,"code":1109,"language":413,"meta":7},[411],".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",[1111],{"type":27,"tag":416,"props":1112,"children":1113},{"__ignoreMap":7},[1114],{"type":32,"value":1109},{"type":27,"tag":65,"props":1116,"children":1118},{"id":1117},"复选框和单选按钮",[1119],{"type":32,"value":1117},{"type":27,"tag":408,"props":1121,"children":1124},{"className":1122,"code":1123,"language":413,"meta":7},[411],".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",[1125],{"type":27,"tag":416,"props":1126,"children":1127},{"__ignoreMap":7},[1128],{"type":32,"value":1123},{"type":27,"tag":65,"props":1130,"children":1132},{"id":1131},"文本区域",[1133],{"type":32,"value":1131},{"type":27,"tag":408,"props":1135,"children":1138},{"className":1136,"code":1137,"language":413,"meta":7},[411],".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",[1139],{"type":27,"tag":416,"props":1140,"children":1141},{"__ignoreMap":7},[1142],{"type":32,"value":1137},{"type":27,"tag":65,"props":1144,"children":1146},{"id":1145},"完整表单示例",[1147],{"type":32,"value":1145},{"type":27,"tag":408,"props":1149,"children":1152},{"className":1150,"code":1151,"language":465,"meta":7},[463],"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",[1153],{"type":27,"tag":416,"props":1154,"children":1155},{"__ignoreMap":7},[1156],{"type":32,"value":1151},{"type":27,"tag":65,"props":1158,"children":1159},{"id":547},[1160],{"type":32,"value":547},{"type":27,"tag":28,"props":1162,"children":1163},{},[1164,1165,1169],{"type":32,"value":554},{"type":27,"tag":556,"props":1166,"children":1167},{},[1168],{"type":32,"value":560},{"type":32,"value":562},{"type":27,"tag":35,"props":1171,"children":1172},{},[1173,1178,1183,1188,1192],{"type":27,"tag":39,"props":1174,"children":1175},{},[1176],{"type":32,"value":1177},"使用正确的输入类型",{"type":27,"tag":39,"props":1179,"children":1180},{},[1181],{"type":32,"value":1182},"提供实时验证反馈",{"type":27,"tag":39,"props":1184,"children":1185},{},[1186],{"type":32,"value":1187},"清晰的标签和提示",{"type":27,"tag":39,"props":1189,"children":1190},{},[1191],{"type":32,"value":570},{"type":27,"tag":39,"props":1193,"children":1194},{},[1195],{"type":32,"value":596},{"type":27,"tag":28,"props":1197,"children":1198},{},[1199,1200,1204],{"type":32,"value":601},{"type":27,"tag":556,"props":1201,"children":1202},{},[1203],{"type":32,"value":606},{"type":32,"value":562},{"type":27,"tag":35,"props":1206,"children":1207},{},[1208,1213,1218,1223,1228],{"type":27,"tag":39,"props":1209,"children":1210},{},[1211],{"type":32,"value":1212},"隐藏标签",{"type":27,"tag":39,"props":1214,"children":1215},{},[1216],{"type":32,"value":1217},"过度使用占位符",{"type":27,"tag":39,"props":1219,"children":1220},{},[1221],{"type":32,"value":1222},"验证后立即提交",{"type":27,"tag":39,"props":1224,"children":1225},{},[1226],{"type":32,"value":1227},"忽视无障碍性",{"type":27,"tag":39,"props":1229,"children":1230},{},[1231],{"type":32,"value":1232},"复杂的验证规则",{"type":27,"tag":65,"props":1234,"children":1235},{"id":653},[1236],{"type":32,"value":653},{"type":27,"tag":35,"props":1238,"children":1240},{"className":1239},[659],[1241,1250,1259,1268,1277,1286],{"type":27,"tag":39,"props":1242,"children":1244},{"className":1243},[664],[1245,1248],{"type":27,"tag":667,"props":1246,"children":1247},{"disabled":669,"type":670},[],{"type":32,"value":1249}," 所有控件都可用键盘导航",{"type":27,"tag":39,"props":1251,"children":1253},{"className":1252},[664],[1254,1257],{"type":27,"tag":667,"props":1255,"children":1256},{"disabled":669,"type":670},[],{"type":32,"value":1258}," 标签与输入框关联",{"type":27,"tag":39,"props":1260,"children":1262},{"className":1261},[664],[1263,1266],{"type":27,"tag":667,"props":1264,"children":1265},{"disabled":669,"type":670},[],{"type":32,"value":1267}," 验证消息清晰",{"type":27,"tag":39,"props":1269,"children":1271},{"className":1270},[664],[1272,1275],{"type":27,"tag":667,"props":1273,"children":1274},{"disabled":669,"type":670},[],{"type":32,"value":1276}," 色彩对比度足够",{"type":27,"tag":39,"props":1278,"children":1280},{"className":1279},[664],[1281,1284],{"type":27,"tag":667,"props":1282,"children":1283},{"disabled":669,"type":670},[],{"type":32,"value":1285}," 屏幕阅读器兼容",{"type":27,"tag":39,"props":1287,"children":1289},{"className":1288},[664],[1290,1293],{"type":27,"tag":667,"props":1291,"children":1292},{"disabled":669,"type":670},[],{"type":32,"value":1294}," 移动设备测试",{"title":7,"searchDepth":354,"depth":354,"links":1296},[1297,1298,1302,1303,1304,1305,1306,1307,1308],{"id":1035,"depth":357,"text":1035},{"id":1057,"depth":357,"text":1057,"children":1299},[1300,1301],{"id":1062,"depth":354,"text":1062},{"id":1076,"depth":354,"text":1076},{"id":1041,"depth":357,"text":1041},{"id":1103,"depth":357,"text":1103},{"id":1117,"depth":357,"text":1117},{"id":1131,"depth":357,"text":1131},{"id":1145,"depth":357,"text":1145},{"id":547,"depth":357,"text":547},{"id":653,"depth":357,"text":653},"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":1313,"image":18,"imageQuery":19,"pexelsPhotoId":20,"pexelsUrl":21,"featured":6,"readingTime":22,"body":1314,"_type":364,"_id":365,"_source":366,"_file":367,"_stem":368,"_extension":369},[13,14,15,16,17],{"type":24,"children":1315,"toc":1573},[1316,1320,1335,1339,1343,1347,1351,1366,1370,1374,1378,1382,1401,1405,1409,1413,1417,1436,1440,1444,1448,1452,1471,1475,1479,1483,1487,1506,1510,1514,1537,1541,1545,1549],{"type":27,"tag":28,"props":1317,"children":1318},{},[1319],{"type":32,"value":33},{"type":27,"tag":35,"props":1321,"children":1322},{},[1323,1327,1331],{"type":27,"tag":39,"props":1324,"children":1325},{},[1326],{"type":32,"value":43},{"type":27,"tag":39,"props":1328,"children":1329},{},[1330],{"type":32,"value":48},{"type":27,"tag":39,"props":1332,"children":1333},{},[1334],{"type":32,"value":53},{"type":27,"tag":28,"props":1336,"children":1337},{},[1338],{"type":32,"value":58},{"type":27,"tag":28,"props":1340,"children":1341},{},[1342],{"type":32,"value":63},{"type":27,"tag":65,"props":1344,"children":1345},{"id":67},[1346],{"type":32,"value":70},{"type":27,"tag":28,"props":1348,"children":1349},{},[1350],{"type":32,"value":75},{"type":27,"tag":35,"props":1352,"children":1353},{},[1354,1358,1362],{"type":27,"tag":39,"props":1355,"children":1356},{},[1357],{"type":32,"value":83},{"type":27,"tag":39,"props":1359,"children":1360},{},[1361],{"type":32,"value":88},{"type":27,"tag":39,"props":1363,"children":1364},{},[1365],{"type":32,"value":93},{"type":27,"tag":28,"props":1367,"children":1368},{},[1369],{"type":32,"value":98},{"type":27,"tag":65,"props":1371,"children":1372},{"id":101},[1373],{"type":32,"value":104},{"type":27,"tag":28,"props":1375,"children":1376},{},[1377],{"type":32,"value":109},{"type":27,"tag":28,"props":1379,"children":1380},{},[1381],{"type":32,"value":114},{"type":27,"tag":35,"props":1383,"children":1384},{},[1385,1389,1393,1397],{"type":27,"tag":39,"props":1386,"children":1387},{},[1388],{"type":32,"value":122},{"type":27,"tag":39,"props":1390,"children":1391},{},[1392],{"type":32,"value":127},{"type":27,"tag":39,"props":1394,"children":1395},{},[1396],{"type":32,"value":132},{"type":27,"tag":39,"props":1398,"children":1399},{},[1400],{"type":32,"value":137},{"type":27,"tag":28,"props":1402,"children":1403},{},[1404],{"type":32,"value":142},{"type":27,"tag":65,"props":1406,"children":1407},{"id":145},[1408],{"type":32,"value":148},{"type":27,"tag":28,"props":1410,"children":1411},{},[1412],{"type":32,"value":153},{"type":27,"tag":28,"props":1414,"children":1415},{},[1416],{"type":32,"value":158},{"type":27,"tag":35,"props":1418,"children":1419},{},[1420,1424,1428,1432],{"type":27,"tag":39,"props":1421,"children":1422},{},[1423],{"type":32,"value":166},{"type":27,"tag":39,"props":1425,"children":1426},{},[1427],{"type":32,"value":171},{"type":27,"tag":39,"props":1429,"children":1430},{},[1431],{"type":32,"value":176},{"type":27,"tag":39,"props":1433,"children":1434},{},[1435],{"type":32,"value":181},{"type":27,"tag":28,"props":1437,"children":1438},{},[1439],{"type":32,"value":186},{"type":27,"tag":65,"props":1441,"children":1442},{"id":189},[1443],{"type":32,"value":189},{"type":27,"tag":28,"props":1445,"children":1446},{},[1447],{"type":32,"value":196},{"type":27,"tag":28,"props":1449,"children":1450},{},[1451],{"type":32,"value":201},{"type":27,"tag":35,"props":1453,"children":1454},{},[1455,1459,1463,1467],{"type":27,"tag":39,"props":1456,"children":1457},{},[1458],{"type":32,"value":209},{"type":27,"tag":39,"props":1460,"children":1461},{},[1462],{"type":32,"value":214},{"type":27,"tag":39,"props":1464,"children":1465},{},[1466],{"type":32,"value":219},{"type":27,"tag":39,"props":1468,"children":1469},{},[1470],{"type":32,"value":224},{"type":27,"tag":28,"props":1472,"children":1473},{},[1474],{"type":32,"value":229},{"type":27,"tag":65,"props":1476,"children":1477},{"id":232},[1478],{"type":32,"value":235},{"type":27,"tag":28,"props":1480,"children":1481},{},[1482],{"type":32,"value":240},{"type":27,"tag":28,"props":1484,"children":1485},{},[1486],{"type":32,"value":245},{"type":27,"tag":35,"props":1488,"children":1489},{},[1490,1494,1498,1502],{"type":27,"tag":39,"props":1491,"children":1492},{},[1493],{"type":32,"value":253},{"type":27,"tag":39,"props":1495,"children":1496},{},[1497],{"type":32,"value":258},{"type":27,"tag":39,"props":1499,"children":1500},{},[1501],{"type":32,"value":263},{"type":27,"tag":39,"props":1503,"children":1504},{},[1505],{"type":32,"value":268},{"type":27,"tag":28,"props":1507,"children":1508},{},[1509],{"type":32,"value":273},{"type":27,"tag":65,"props":1511,"children":1512},{"id":276},[1513],{"type":32,"value":276},{"type":27,"tag":35,"props":1515,"children":1516},{},[1517,1521,1525,1529,1533],{"type":27,"tag":39,"props":1518,"children":1519},{},[1520],{"type":32,"value":286},{"type":27,"tag":39,"props":1522,"children":1523},{},[1524],{"type":32,"value":291},{"type":27,"tag":39,"props":1526,"children":1527},{},[1528],{"type":32,"value":296},{"type":27,"tag":39,"props":1530,"children":1531},{},[1532],{"type":32,"value":301},{"type":27,"tag":39,"props":1534,"children":1535},{},[1536],{"type":32,"value":306},{"type":27,"tag":65,"props":1538,"children":1539},{"id":309},[1540],{"type":32,"value":309},{"type":27,"tag":28,"props":1542,"children":1543},{},[1544],{"type":32,"value":316},{"type":27,"tag":28,"props":1546,"children":1547},{},[1548],{"type":32,"value":321},{"type":27,"tag":35,"props":1550,"children":1551},{},[1552,1559,1566],{"type":27,"tag":39,"props":1553,"children":1554},{},[1555],{"type":27,"tag":329,"props":1556,"children":1557},{"href":331},[1558],{"type":32,"value":334},{"type":27,"tag":39,"props":1560,"children":1561},{},[1562],{"type":27,"tag":329,"props":1563,"children":1564},{"href":340},[1565],{"type":32,"value":343},{"type":27,"tag":39,"props":1567,"children":1568},{},[1569],{"type":27,"tag":329,"props":1570,"children":1571},{"href":349},[1572],{"type":32,"value":352},{"title":7,"searchDepth":354,"depth":354,"links":1574},[1575,1576,1577,1578,1579,1580,1581],{"id":67,"depth":357,"text":70},{"id":101,"depth":357,"text":104},{"id":145,"depth":357,"text":148},{"id":189,"depth":357,"text":189},{"id":232,"depth":357,"text":235},{"id":276,"depth":357,"text":276},{"id":309,"depth":357,"text":309},1777086813679]