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