[{"data":1,"prerenderedAt":2262},["ShallowReactive",2],{"article-/topics/design/form-component-design-specification":3,"related-design":745,"content-query-GN01fxz8wH":1686},{"_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":739,"_id":740,"_source":741,"_file":742,"_stem":743,"_extension":744},"/topics/design/form-component-design-specification","design",false,"","表单组件设计完整规范：状态、校验、反馈与协作边界一次讲清","很多团队有表单组件，却没有表单规范。本文从状态定义、校验节奏、错误提示、API 约束和设计协作入手，讲清怎样把表单组件从“能用”推进到“可持续维护”。","2026-04-14","HTMLPAGE 团队",[13,14,15,16,17],"Form Design","Design System","Component Spec","UX","Frontend","/images/topics/design/form-component-design-specification.jpg","designer working on form interface in laptop ui workspace",16323439,"https://www.pexels.com/photo/man-sitting-by-desk-and-drawing-on-tablet-16323439/",14,{"type":24,"children":25,"toc":727},"root",[26,34,39,93,98,127,134,139,144,248,267,273,278,283,302,307,325,330,336,341,346,364,369,394,399,417,423,428,433,494,499,505,526,559,564,582,587,605,610,615,620,638,643,648,686,691,696,701],{"type":27,"tag":28,"props":29,"children":30},"element","p",{},[31],{"type":32,"value":33},"text","很多团队在做设计系统时，最容易高估“有组件”这件事的完成度。",{"type":27,"tag":28,"props":35,"children":36},{},[37],{"type":32,"value":38},"输入框、选择器、日期组件、提交按钮都做出来了，看起来像是拥有了一套表单能力。但只要一进入真实业务，很快就会出现这些问题：",{"type":27,"tag":40,"props":41,"children":42},"ul",{},[43,49,83,88],{"type":27,"tag":44,"props":45,"children":46},"li",{},[47],{"type":32,"value":48},"同样是必填错误，不同页面的提示位置和语气完全不同",{"type":27,"tag":44,"props":50,"children":51},{},[52,59,61,67,68,74,75,81],{"type":27,"tag":53,"props":54,"children":56},"code",{"className":55},[],[57],{"type":32,"value":58},"disabled",{"type":32,"value":60},"、",{"type":27,"tag":53,"props":62,"children":64},{"className":63},[],[65],{"type":32,"value":66},"readonly",{"type":32,"value":60},{"type":27,"tag":53,"props":69,"children":71},{"className":70},[],[72],{"type":32,"value":73},"loading",{"type":32,"value":60},{"type":27,"tag":53,"props":76,"children":78},{"className":77},[],[79],{"type":32,"value":80},"invalid",{"type":32,"value":82}," 的行为定义各不相同",{"type":27,"tag":44,"props":84,"children":85},{},[86],{"type":32,"value":87},"设计稿里只有静态样式，没有校验节奏和异常场景",{"type":27,"tag":44,"props":89,"children":90},{},[91],{"type":32,"value":92},"组件 props 越来越多，但谁也说不清哪些是规范能力，哪些只是历史兼容",{"type":27,"tag":28,"props":94,"children":95},{},[96],{"type":32,"value":97},"所以这篇文章不再讲“表单组件有哪些”，而是专门讲规范：怎样把表单组件做成一套可协作、可扩展、可回归的系统。",{"type":27,"tag":28,"props":99,"children":100},{},[101,103,110,111,117,119,125],{"type":32,"value":102},"如果你想先补组件体系基础，可以先看 ",{"type":27,"tag":104,"props":105,"children":107},"a",{"href":106},"/topics/design/form-component-system-guide",[108],{"type":32,"value":109},"表单组件设计系统完全指南",{"type":32,"value":60},{"type":27,"tag":104,"props":112,"children":114},{"href":113},"/topics/frontend/complex-form-logic-guide",[115],{"type":32,"value":116},"复杂表单业务逻辑管理",{"type":32,"value":118}," 和 ",{"type":27,"tag":104,"props":120,"children":122},{"href":121},"/topics/frontend/vue-landing-form-best-practices",[123],{"type":32,"value":124},"Vue 做落地页结构、表单、埋点",{"type":32,"value":126},"。",{"type":27,"tag":128,"props":129,"children":131},"h2",{"id":130},"先定义-4-类状态不然后面所有讨论都会混乱",[132],{"type":32,"value":133},"先定义 4 类状态，不然后面所有讨论都会混乱",{"type":27,"tag":28,"props":135,"children":136},{},[137],{"type":32,"value":138},"表单规范的第一步，不是写样式，而是先把状态语言统一。",{"type":27,"tag":28,"props":140,"children":141},{},[142],{"type":32,"value":143},"我更建议每个基础字段都至少定义这 4 类状态：",{"type":27,"tag":145,"props":146,"children":147},"table",{},[148,172],{"type":27,"tag":149,"props":150,"children":151},"thead",{},[152],{"type":27,"tag":153,"props":154,"children":155},"tr",{},[156,162,167],{"type":27,"tag":157,"props":158,"children":159},"th",{},[160],{"type":32,"value":161},"状态",{"type":27,"tag":157,"props":163,"children":164},{},[165],{"type":32,"value":166},"含义",{"type":27,"tag":157,"props":168,"children":169},{},[170],{"type":32,"value":171},"用户可见变化",{"type":27,"tag":173,"props":174,"children":175},"tbody",{},[176,195,213,230],{"type":27,"tag":153,"props":177,"children":178},{},[179,185,190],{"type":27,"tag":180,"props":181,"children":182},"td",{},[183],{"type":32,"value":184},"default",{"type":27,"tag":180,"props":186,"children":187},{},[188],{"type":32,"value":189},"初始可输入状态",{"type":27,"tag":180,"props":191,"children":192},{},[193],{"type":32,"value":194},"正常边框、正常提示",{"type":27,"tag":153,"props":196,"children":197},{},[198,203,208],{"type":27,"tag":180,"props":199,"children":200},{},[201],{"type":32,"value":202},"focus",{"type":27,"tag":180,"props":204,"children":205},{},[206],{"type":32,"value":207},"当前正在交互",{"type":27,"tag":180,"props":209,"children":210},{},[211],{"type":32,"value":212},"高亮边框、辅助说明更明确",{"type":27,"tag":153,"props":214,"children":215},{},[216,220,225],{"type":27,"tag":180,"props":217,"children":218},{},[219],{"type":32,"value":80},{"type":27,"tag":180,"props":221,"children":222},{},[223],{"type":32,"value":224},"当前值不满足规则",{"type":27,"tag":180,"props":226,"children":227},{},[228],{"type":32,"value":229},"错误信息、危险色、必要时图标",{"type":27,"tag":153,"props":231,"children":232},{},[233,238,243],{"type":27,"tag":180,"props":234,"children":235},{},[236],{"type":32,"value":237},"disabled / readonly",{"type":27,"tag":180,"props":239,"children":240},{},[241],{"type":32,"value":242},"当前不能改或只能看",{"type":27,"tag":180,"props":244,"children":245},{},[246],{"type":32,"value":247},"降低可点击感、避免误导",{"type":27,"tag":28,"props":249,"children":250},{},[251,253,258,259,265],{"type":32,"value":252},"很多系统把 ",{"type":27,"tag":53,"props":254,"children":256},{"className":255},[],[257],{"type":32,"value":73},{"type":32,"value":118},{"type":27,"tag":53,"props":260,"children":262},{"className":261},[],[263],{"type":32,"value":264},"success",{"type":32,"value":266}," 也塞进字段状态里，但更稳的做法是把它们定义为“表单级反馈”或“提交级反馈”，不要让单字段状态无限膨胀。",{"type":27,"tag":128,"props":268,"children":270},{"id":269},"校验规范最怕的不是规则少而是时机乱",[271],{"type":32,"value":272},"校验规范最怕的不是规则少，而是时机乱",{"type":27,"tag":28,"props":274,"children":275},{},[276],{"type":32,"value":277},"同一条规则，如果在不同时间点触发，体验完全不同。",{"type":27,"tag":28,"props":279,"children":280},{},[281],{"type":32,"value":282},"建议把校验分成三层：",{"type":27,"tag":284,"props":285,"children":286},"ol",{},[287,292,297],{"type":27,"tag":44,"props":288,"children":289},{},[290],{"type":32,"value":291},"输入期：字符数、格式趋势、密码强度",{"type":27,"tag":44,"props":293,"children":294},{},[295],{"type":32,"value":296},"失焦期：邮箱、手机号、日期格式这类可立即判断的问题",{"type":27,"tag":44,"props":298,"children":299},{},[300],{"type":32,"value":301},"提交期：跨字段依赖、业务约束、服务端校验",{"type":27,"tag":28,"props":303,"children":304},{},[305],{"type":32,"value":306},"这背后的原则是：",{"type":27,"tag":40,"props":308,"children":309},{},[310,315,320],{"type":27,"tag":44,"props":311,"children":312},{},[313],{"type":32,"value":314},"用户还在输入时，不要过早打断",{"type":27,"tag":44,"props":316,"children":317},{},[318],{"type":32,"value":319},"用户离开字段时，要给出明确且可行动的反馈",{"type":27,"tag":44,"props":321,"children":322},{},[323],{"type":32,"value":324},"提交时，再处理真正需要整体判断的规则",{"type":27,"tag":28,"props":326,"children":327},{},[328],{"type":32,"value":329},"如果团队不把触发时机写进规范，最终每个业务线都会按自己的“感觉”实现。",{"type":27,"tag":128,"props":331,"children":333},{"id":332},"错误提示不是文案问题而是路径问题",[334],{"type":32,"value":335},"错误提示不是文案问题，而是路径问题",{"type":27,"tag":28,"props":337,"children":338},{},[339],{"type":32,"value":340},"很多表单体验差，不是因为颜色不好看，而是因为用户不知道下一步做什么。",{"type":27,"tag":28,"props":342,"children":343},{},[344],{"type":32,"value":345},"一个更可靠的错误提示规范应包含 3 件事：",{"type":27,"tag":40,"props":347,"children":348},{},[349,354,359],{"type":27,"tag":44,"props":350,"children":351},{},[352],{"type":32,"value":353},"指出哪里错了",{"type":27,"tag":44,"props":355,"children":356},{},[357],{"type":32,"value":358},"说明为什么错",{"type":27,"tag":44,"props":360,"children":361},{},[362],{"type":32,"value":363},"告诉用户如何改",{"type":27,"tag":28,"props":365,"children":366},{},[367],{"type":32,"value":368},"例如：",{"type":27,"tag":40,"props":370,"children":371},{},[372,383],{"type":27,"tag":44,"props":373,"children":374},{},[375,377],{"type":32,"value":376},"不推荐：",{"type":27,"tag":53,"props":378,"children":380},{"className":379},[],[381],{"type":32,"value":382},"输入无效",{"type":27,"tag":44,"props":384,"children":385},{},[386,388],{"type":32,"value":387},"更可用：",{"type":27,"tag":53,"props":389,"children":391},{"className":390},[],[392],{"type":32,"value":393},"邮箱格式不正确，请检查 @ 和域名是否完整",{"type":27,"tag":28,"props":395,"children":396},{},[397],{"type":32,"value":398},"如果是服务端错误，还应区分：",{"type":27,"tag":40,"props":400,"children":401},{},[402,407,412],{"type":27,"tag":44,"props":403,"children":404},{},[405],{"type":32,"value":406},"字段级错误：靠近字段展示",{"type":27,"tag":44,"props":408,"children":409},{},[410],{"type":32,"value":411},"表单级错误：放在提交区或顶部摘要",{"type":27,"tag":44,"props":413,"children":414},{},[415],{"type":32,"value":416},"系统级错误：用 toast 或全局提示，避免混淆为用户填错",{"type":27,"tag":128,"props":418,"children":420},{"id":419},"组件-api-要控制在表达清楚不要无限兼容",[421],{"type":32,"value":422},"组件 API 要控制在“表达清楚”，不要无限兼容",{"type":27,"tag":28,"props":424,"children":425},{},[426],{"type":32,"value":427},"表单组件最常见的失控方式，是 props 越加越多。",{"type":27,"tag":28,"props":429,"children":430},{},[431],{"type":32,"value":432},"建议在规范里明确分层：",{"type":27,"tag":145,"props":434,"children":435},{},[436,452],{"type":27,"tag":149,"props":437,"children":438},{},[439],{"type":27,"tag":153,"props":440,"children":441},{},[442,447],{"type":27,"tag":157,"props":443,"children":444},{},[445],{"type":32,"value":446},"类型",{"type":27,"tag":157,"props":448,"children":449},{},[450],{"type":32,"value":451},"应该承载什么",{"type":27,"tag":173,"props":453,"children":454},{},[455,468,481],{"type":27,"tag":153,"props":456,"children":457},{},[458,463],{"type":27,"tag":180,"props":459,"children":460},{},[461],{"type":32,"value":462},"基础输入组件",{"type":27,"tag":180,"props":464,"children":465},{},[466],{"type":32,"value":467},"值、占位、只读、禁用、状态",{"type":27,"tag":153,"props":469,"children":470},{},[471,476],{"type":27,"tag":180,"props":472,"children":473},{},[474],{"type":32,"value":475},"字段容器组件",{"type":27,"tag":180,"props":477,"children":478},{},[479],{"type":32,"value":480},"label、help、error、required",{"type":27,"tag":153,"props":482,"children":483},{},[484,489],{"type":27,"tag":180,"props":485,"children":486},{},[487],{"type":32,"value":488},"业务组合组件",{"type":27,"tag":180,"props":490,"children":491},{},[492],{"type":32,"value":493},"特定场景的默认规则和交互",{"type":27,"tag":28,"props":495,"children":496},{},[497],{"type":32,"value":498},"这样做的好处是，基础组件不需要知道所有业务文案和复杂校验，业务层也不会反过来污染基础能力。",{"type":27,"tag":128,"props":500,"children":502},{"id":501},"失败案例把所有表单差异都压进一个万能组件",[503],{"type":32,"value":504},"失败案例：把所有表单差异都压进一个万能组件",{"type":27,"tag":28,"props":506,"children":507},{},[508,510,516,518,524],{"type":32,"value":509},"很多团队都做过一个叫 ",{"type":27,"tag":53,"props":511,"children":513},{"className":512},[],[514],{"type":32,"value":515},"FormField",{"type":32,"value":517}," 或 ",{"type":27,"tag":53,"props":519,"children":521},{"className":520},[],[522],{"type":32,"value":523},"BaseInput",{"type":32,"value":525}," 的超级组件，最后支持：",{"type":27,"tag":40,"props":527,"children":528},{},[529,534,539,544,549,554],{"type":27,"tag":44,"props":530,"children":531},{},[532],{"type":32,"value":533},"左右图标",{"type":27,"tag":44,"props":535,"children":536},{},[537],{"type":32,"value":538},"多种 label 布局",{"type":27,"tag":44,"props":540,"children":541},{},[542],{"type":32,"value":543},"各类校验时机",{"type":27,"tag":44,"props":545,"children":546},{},[547],{"type":32,"value":548},"多种异步查询",{"type":27,"tag":44,"props":550,"children":551},{},[552],{"type":32,"value":553},"字段联动",{"type":27,"tag":44,"props":555,"children":556},{},[557],{"type":32,"value":558},"业务埋点",{"type":27,"tag":28,"props":560,"children":561},{},[562],{"type":32,"value":563},"结果是：",{"type":27,"tag":40,"props":565,"children":566},{},[567,572,577],{"type":27,"tag":44,"props":568,"children":569},{},[570],{"type":32,"value":571},"文档很难写清楚",{"type":27,"tag":44,"props":573,"children":574},{},[575],{"type":32,"value":576},"改一个状态影响多个业务",{"type":27,"tag":44,"props":578,"children":579},{},[580],{"type":32,"value":581},"reviewer 很难判断回归范围",{"type":27,"tag":28,"props":583,"children":584},{},[585],{"type":32,"value":586},"更稳的方式是：",{"type":27,"tag":40,"props":588,"children":589},{},[590,595,600],{"type":27,"tag":44,"props":591,"children":592},{},[593],{"type":32,"value":594},"基础字段组件只做输入行为",{"type":27,"tag":44,"props":596,"children":597},{},[598],{"type":32,"value":599},"规范组件统一承载 label/help/error",{"type":27,"tag":44,"props":601,"children":602},{},[603],{"type":32,"value":604},"复杂业务场景另做组合层封装",{"type":27,"tag":28,"props":606,"children":607},{},[608],{"type":32,"value":609},"不要把“组件复用”误解成“所有变化都塞进同一个组件”。",{"type":27,"tag":128,"props":611,"children":613},{"id":612},"设计与前端的协作边界也要写进规范",[614],{"type":32,"value":612},{"type":27,"tag":28,"props":616,"children":617},{},[618],{"type":32,"value":619},"真正能长期落地的表单规范，不会只停留在 Figma 或代码仓库里，而会把双方责任讲清楚：",{"type":27,"tag":40,"props":621,"children":622},{},[623,628,633],{"type":27,"tag":44,"props":624,"children":625},{},[626],{"type":32,"value":627},"设计负责：视觉层级、状态稿、错误样式、间距和层级规则",{"type":27,"tag":44,"props":629,"children":630},{},[631],{"type":32,"value":632},"前端负责：组件 API、状态机、校验节奏、无障碍行为",{"type":27,"tag":44,"props":634,"children":635},{},[636],{"type":32,"value":637},"产品负责：哪些字段必须收集、哪些校验属于业务约束",{"type":27,"tag":28,"props":639,"children":640},{},[641],{"type":32,"value":642},"如果三方没有共识，最后最容易变成“设计只有静态稿，前端靠猜补动态逻辑”。",{"type":27,"tag":128,"props":644,"children":646},{"id":645},"一份可直接复用的检查清单",[647],{"type":32,"value":645},{"type":27,"tag":40,"props":649,"children":650},{},[651,656,661,666,671,676,681],{"type":27,"tag":44,"props":652,"children":653},{},[654],{"type":32,"value":655},"基础字段是否定义了 default、focus、invalid、disabled/readonly 状态",{"type":27,"tag":44,"props":657,"children":658},{},[659],{"type":32,"value":660},"校验触发时机是否写清输入期、失焦期、提交期",{"type":27,"tag":44,"props":662,"children":663},{},[664],{"type":32,"value":665},"错误提示是否能指导用户修正，而不是只给抽象判断",{"type":27,"tag":44,"props":667,"children":668},{},[669],{"type":32,"value":670},"字段级错误和表单级错误是否有清晰分工",{"type":27,"tag":44,"props":672,"children":673},{},[674],{"type":32,"value":675},"组件 API 是否控制在基础能力边界内",{"type":27,"tag":44,"props":677,"children":678},{},[679],{"type":32,"value":680},"设计稿里是否包含空态、错误态、加载态和成功反馈",{"type":27,"tag":44,"props":682,"children":683},{},[684],{"type":32,"value":685},"无障碍细节是否覆盖 label 关联、错误朗读、键盘操作",{"type":27,"tag":128,"props":687,"children":689},{"id":688},"总结",[690],{"type":32,"value":688},{"type":27,"tag":28,"props":692,"children":693},{},[694],{"type":32,"value":695},"表单组件的真正难点，从来不是样式，而是规范。只有把状态定义、校验时机、错误路径、API 边界和协作分工一起写清楚，表单系统才会从“重复救火”走向“稳定复用”。",{"type":27,"tag":28,"props":697,"children":698},{},[699],{"type":32,"value":700},"进一步阅读：",{"type":27,"tag":40,"props":702,"children":703},{},[704,711,718],{"type":27,"tag":44,"props":705,"children":706},{},[707],{"type":27,"tag":104,"props":708,"children":709},{"href":106},[710],{"type":32,"value":109},{"type":27,"tag":44,"props":712,"children":713},{},[714],{"type":27,"tag":104,"props":715,"children":716},{"href":113},[717],{"type":32,"value":116},{"type":27,"tag":44,"props":719,"children":720},{},[721],{"type":27,"tag":104,"props":722,"children":724},{"href":723},"/topics/design/accessibility-design-guide",[725],{"type":32,"value":726},"无障碍设计指南",{"title":7,"searchDepth":728,"depth":728,"links":729},3,[730,732,733,734,735,736,737,738],{"id":130,"depth":731,"text":133},2,{"id":269,"depth":731,"text":272},{"id":332,"depth":731,"text":335},{"id":419,"depth":731,"text":422},{"id":501,"depth":731,"text":504},{"id":612,"depth":731,"text":612},{"id":645,"depth":731,"text":645},{"id":688,"depth":731,"text":688},"markdown","content:topics:design:form-component-design-specification.md","content","topics/design/form-component-design-specification.md","topics/design/form-component-design-specification","md",[746,1105,1407],{"_path":747,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":748,"description":749,"keywords":750,"image":756,"author":11,"date":757,"readingTime":758,"topic":5,"body":759,"_type":739,"_id":1102,"_source":741,"_file":1103,"_stem":1104,"_extension":744},"/topics/design/button-component-design","按钮组件设计详解","学习按钮样式、交互状态、无障碍性和最佳实践",[751,752,753,754,755],"按钮设计","Button Component","交互状态","UI 组件","用户体验","/images/topics/button-design.jpg","2025-12-08",18,{"type":24,"children":760,"toc":1084},[761,765,770,775,782,794,800,809,815,824,828,834,845,851,860,866,875,880,889,894,905,910,919,924,937,971,982,1025,1030],{"type":27,"tag":128,"props":762,"children":763},{"id":748},[764],{"type":32,"value":748},{"type":27,"tag":28,"props":766,"children":767},{},[768],{"type":32,"value":769},"按钮是 UI 中最重要的交互元素。优秀的按钮设计能够指导用户行为。",{"type":27,"tag":128,"props":771,"children":773},{"id":772},"按钮类型",[774],{"type":32,"value":772},{"type":27,"tag":776,"props":777,"children":779},"h3",{"id":778},"primary-button主按钮",[780],{"type":32,"value":781},"Primary Button（主按钮）",{"type":27,"tag":783,"props":784,"children":789},"pre",{"className":785,"code":787,"language":788,"meta":7},[786],"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",[790],{"type":27,"tag":53,"props":791,"children":792},{"__ignoreMap":7},[793],{"type":32,"value":787},{"type":27,"tag":776,"props":795,"children":797},{"id":796},"secondary-button次按钮",[798],{"type":32,"value":799},"Secondary Button（次按钮）",{"type":27,"tag":783,"props":801,"children":804},{"className":802,"code":803,"language":788,"meta":7},[786],".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",[805],{"type":27,"tag":53,"props":806,"children":807},{"__ignoreMap":7},[808],{"type":32,"value":803},{"type":27,"tag":776,"props":810,"children":812},{"id":811},"danger-button危险按钮",[813],{"type":32,"value":814},"Danger Button（危险按钮）",{"type":27,"tag":783,"props":816,"children":819},{"className":817,"code":818,"language":788,"meta":7},[786],".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",[820],{"type":27,"tag":53,"props":821,"children":822},{"__ignoreMap":7},[823],{"type":32,"value":818},{"type":27,"tag":128,"props":825,"children":826},{"id":753},[827],{"type":32,"value":753},{"type":27,"tag":776,"props":829,"children":831},{"id":830},"loading-状态",[832],{"type":32,"value":833},"Loading 状态",{"type":27,"tag":783,"props":835,"children":840},{"className":836,"code":838,"language":839,"meta":7},[837],"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",[841],{"type":27,"tag":53,"props":842,"children":843},{"__ignoreMap":7},[844],{"type":32,"value":838},{"type":27,"tag":776,"props":846,"children":848},{"id":847},"disabled-状态",[849],{"type":32,"value":850},"Disabled 状态",{"type":27,"tag":783,"props":852,"children":855},{"className":853,"code":854,"language":788,"meta":7},[786],".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",[856],{"type":27,"tag":53,"props":857,"children":858},{"__ignoreMap":7},[859],{"type":32,"value":854},{"type":27,"tag":776,"props":861,"children":863},{"id":862},"focus-状态",[864],{"type":32,"value":865},"Focus 状态",{"type":27,"tag":783,"props":867,"children":870},{"className":868,"code":869,"language":788,"meta":7},[786],".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",[871],{"type":27,"tag":53,"props":872,"children":873},{"__ignoreMap":7},[874],{"type":32,"value":869},{"type":27,"tag":128,"props":876,"children":878},{"id":877},"按钮大小",[879],{"type":32,"value":877},{"type":27,"tag":783,"props":881,"children":884},{"className":882,"code":883,"language":788,"meta":7},[786],"/* 小按钮 */\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",[885],{"type":27,"tag":53,"props":886,"children":887},{"__ignoreMap":7},[888],{"type":32,"value":883},{"type":27,"tag":128,"props":890,"children":892},{"id":891},"无障碍性",[893],{"type":32,"value":891},{"type":27,"tag":783,"props":895,"children":900},{"className":896,"code":898,"language":899,"meta":7},[897],"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",[901],{"type":27,"tag":53,"props":902,"children":903},{"__ignoreMap":7},[904],{"type":32,"value":898},{"type":27,"tag":128,"props":906,"children":908},{"id":907},"完整组件示例",[909],{"type":32,"value":907},{"type":27,"tag":783,"props":911,"children":914},{"className":912,"code":913,"language":839,"meta":7},[837],"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",[915],{"type":27,"tag":53,"props":916,"children":917},{"__ignoreMap":7},[918],{"type":32,"value":913},{"type":27,"tag":128,"props":920,"children":922},{"id":921},"最佳实践",[923],{"type":32,"value":921},{"type":27,"tag":28,"props":925,"children":926},{},[927,929,935],{"type":32,"value":928},"✅ ",{"type":27,"tag":930,"props":931,"children":932},"strong",{},[933],{"type":32,"value":934},"应该做的事",{"type":32,"value":936},":",{"type":27,"tag":40,"props":938,"children":939},{},[940,945,950,961,966],{"type":27,"tag":44,"props":941,"children":942},{},[943],{"type":32,"value":944},"最小触摸目标 44x44px",{"type":27,"tag":44,"props":946,"children":947},{},[948],{"type":32,"value":949},"清晰的视觉反馈",{"type":27,"tag":44,"props":951,"children":952},{},[953,955],{"type":32,"value":954},"使用语义 HTML ",{"type":27,"tag":53,"props":956,"children":958},{"className":957},[],[959],{"type":32,"value":960},"\u003Cbutton>",{"type":27,"tag":44,"props":962,"children":963},{},[964],{"type":32,"value":965},"提供加载状态反馈",{"type":27,"tag":44,"props":967,"children":968},{},[969],{"type":32,"value":970},"支持键盘导航",{"type":27,"tag":28,"props":972,"children":973},{},[974,976,981],{"type":32,"value":975},"❌ ",{"type":27,"tag":930,"props":977,"children":978},{},[979],{"type":32,"value":980},"不应该做的事",{"type":32,"value":936},{"type":27,"tag":40,"props":983,"children":984},{},[985,998,1003,1008,1013],{"type":27,"tag":44,"props":986,"children":987},{},[988,990,996],{"type":32,"value":989},"使用 ",{"type":27,"tag":53,"props":991,"children":993},{"className":992},[],[994],{"type":32,"value":995},"\u003Cdiv>",{"type":32,"value":997}," 模拟按钮",{"type":27,"tag":44,"props":999,"children":1000},{},[1001],{"type":32,"value":1002},"隐藏焦点指示器",{"type":27,"tag":44,"props":1004,"children":1005},{},[1006],{"type":32,"value":1007},"过多的按钮样式",{"type":27,"tag":44,"props":1009,"children":1010},{},[1011],{"type":32,"value":1012},"忽视禁用状态",{"type":27,"tag":44,"props":1014,"children":1015},{},[1016,1017,1023],{"type":32,"value":989},{"type":27,"tag":53,"props":1018,"children":1020},{"className":1019},[],[1021],{"type":32,"value":1022},"\u003Ca>",{"type":32,"value":1024}," 代替按钮",{"type":27,"tag":128,"props":1026,"children":1028},{"id":1027},"测试清单",[1029],{"type":32,"value":1027},{"type":27,"tag":40,"props":1031,"children":1034},{"className":1032},[1033],"contains-task-list",[1035,1048,1057,1066,1075],{"type":27,"tag":44,"props":1036,"children":1039},{"className":1037},[1038],"task-list-item",[1040,1046],{"type":27,"tag":1041,"props":1042,"children":1045},"input",{"disabled":1043,"type":1044},true,"checkbox",[],{"type":32,"value":1047}," 在各种浏览器中测试",{"type":27,"tag":44,"props":1049,"children":1051},{"className":1050},[1038],[1052,1055],{"type":27,"tag":1041,"props":1053,"children":1054},{"disabled":1043,"type":1044},[],{"type":32,"value":1056}," 验证键盘导航",{"type":27,"tag":44,"props":1058,"children":1060},{"className":1059},[1038],[1061,1064],{"type":27,"tag":1041,"props":1062,"children":1063},{"disabled":1043,"type":1044},[],{"type":32,"value":1065}," 检查色彩对比度",{"type":27,"tag":44,"props":1067,"children":1069},{"className":1068},[1038],[1070,1073],{"type":27,"tag":1041,"props":1071,"children":1072},{"disabled":1043,"type":1044},[],{"type":32,"value":1074}," 测试触摸设备",{"type":27,"tag":44,"props":1076,"children":1078},{"className":1077},[1038],[1079,1082],{"type":27,"tag":1041,"props":1080,"children":1081},{"disabled":1043,"type":1044},[],{"type":32,"value":1083}," 屏幕阅读器兼容性",{"title":7,"searchDepth":728,"depth":728,"links":1085},[1086,1087,1092,1097,1098,1099,1100,1101],{"id":748,"depth":731,"text":748},{"id":772,"depth":731,"text":772,"children":1088},[1089,1090,1091],{"id":778,"depth":728,"text":781},{"id":796,"depth":728,"text":799},{"id":811,"depth":728,"text":814},{"id":753,"depth":731,"text":753,"children":1093},[1094,1095,1096],{"id":830,"depth":728,"text":833},{"id":847,"depth":728,"text":850},{"id":862,"depth":728,"text":865},{"id":877,"depth":731,"text":877},{"id":891,"depth":731,"text":891},{"id":907,"depth":731,"text":907},{"id":921,"depth":731,"text":921},{"id":1027,"depth":731,"text":1027},"content:topics:design:button-component-design.md","topics/design/button-component-design.md","topics/design/button-component-design",{"_path":1106,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":1107,"description":1108,"keywords":1109,"image":1114,"author":11,"date":757,"readingTime":1115,"topic":5,"body":1116,"_type":739,"_id":1404,"_source":741,"_file":1405,"_stem":1406,"_extension":744},"/topics/design/dark-mode-design","暗黑模式设计完整方案","学习暗黑模式实现、色彩方案、对比度管理和最佳实践",[1110,1111,1112,1113,755],"暗黑模式","Dark Mode","色彩系统","CSS 变量","/images/topics/dark-mode-design.jpg",20,{"type":24,"children":1117,"toc":1387},[1118,1122,1127,1132,1138,1147,1153,1162,1167,1173,1182,1188,1199,1205,1214,1219,1228,1233,1242,1247,1256,1260,1269,1297,1306,1334,1338],{"type":27,"tag":128,"props":1119,"children":1120},{"id":1107},[1121],{"type":32,"value":1107},{"type":27,"tag":28,"props":1123,"children":1124},{},[1125],{"type":32,"value":1126},"暗黑模式已成为现代应用的标准功能。它能够减少眼睛疲劳、节省电池、改善用户体验。",{"type":27,"tag":128,"props":1128,"children":1130},{"id":1129},"核心色彩系统",[1131],{"type":32,"value":1129},{"type":27,"tag":776,"props":1133,"children":1135},{"id":1134},"light-mode-配色",[1136],{"type":32,"value":1137},"Light Mode 配色",{"type":27,"tag":783,"props":1139,"children":1142},{"className":1140,"code":1141,"language":788,"meta":7},[786],":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",[1143],{"type":27,"tag":53,"props":1144,"children":1145},{"__ignoreMap":7},[1146],{"type":32,"value":1141},{"type":27,"tag":776,"props":1148,"children":1150},{"id":1149},"dark-mode-配色",[1151],{"type":32,"value":1152},"Dark Mode 配色",{"type":27,"tag":783,"props":1154,"children":1157},{"className":1155,"code":1156,"language":788,"meta":7},[786],"@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",[1158],{"type":27,"tag":53,"props":1159,"children":1160},{"__ignoreMap":7},[1161],{"type":32,"value":1156},{"type":27,"tag":128,"props":1163,"children":1165},{"id":1164},"实现方案",[1166],{"type":32,"value":1164},{"type":27,"tag":776,"props":1168,"children":1170},{"id":1169},"方案-1prefers-color-scheme",[1171],{"type":32,"value":1172},"方案 1：prefers-color-scheme",{"type":27,"tag":783,"props":1174,"children":1177},{"className":1175,"code":1176,"language":788,"meta":7},[786],"/* 自动跟随系统设置 */\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",[1178],{"type":27,"tag":53,"props":1179,"children":1180},{"__ignoreMap":7},[1181],{"type":32,"value":1176},{"type":27,"tag":776,"props":1183,"children":1185},{"id":1184},"方案-2javascript-切换",[1186],{"type":32,"value":1187},"方案 2：JavaScript 切换",{"type":27,"tag":783,"props":1189,"children":1194},{"className":1190,"code":1192,"language":1193,"meta":7},[1191],"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",[1195],{"type":27,"tag":53,"props":1196,"children":1197},{"__ignoreMap":7},[1198],{"type":32,"value":1192},{"type":27,"tag":776,"props":1200,"children":1202},{"id":1201},"方案-3css-variables-javascript",[1203],{"type":32,"value":1204},"方案 3：CSS Variables + JavaScript",{"type":27,"tag":783,"props":1206,"children":1209},{"className":1207,"code":1208,"language":1193,"meta":7},[1191],"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",[1210],{"type":27,"tag":53,"props":1211,"children":1212},{"__ignoreMap":7},[1213],{"type":32,"value":1208},{"type":27,"tag":128,"props":1215,"children":1217},{"id":1216},"对比度管理",[1218],{"type":32,"value":1216},{"type":27,"tag":783,"props":1220,"children":1223},{"className":1221,"code":1222,"language":788,"meta":7},[786],"/* 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",[1224],{"type":27,"tag":53,"props":1225,"children":1226},{"__ignoreMap":7},[1227],{"type":32,"value":1222},{"type":27,"tag":128,"props":1229,"children":1231},{"id":1230},"图片和图表处理",[1232],{"type":32,"value":1230},{"type":27,"tag":783,"props":1234,"children":1237},{"className":1235,"code":1236,"language":899,"meta":7},[897],"\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",[1238],{"type":27,"tag":53,"props":1239,"children":1240},{"__ignoreMap":7},[1241],{"type":32,"value":1236},{"type":27,"tag":128,"props":1243,"children":1245},{"id":1244},"完整示例",[1246],{"type":32,"value":1244},{"type":27,"tag":783,"props":1248,"children":1251},{"className":1249,"code":1250,"language":839,"meta":7},[837],"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",[1252],{"type":27,"tag":53,"props":1253,"children":1254},{"__ignoreMap":7},[1255],{"type":32,"value":1250},{"type":27,"tag":128,"props":1257,"children":1258},{"id":921},[1259],{"type":32,"value":921},{"type":27,"tag":28,"props":1261,"children":1262},{},[1263,1264,1268],{"type":32,"value":928},{"type":27,"tag":930,"props":1265,"children":1266},{},[1267],{"type":32,"value":934},{"type":32,"value":936},{"type":27,"tag":40,"props":1270,"children":1271},{},[1272,1277,1282,1287,1292],{"type":27,"tag":44,"props":1273,"children":1274},{},[1275],{"type":32,"value":1276},"支持系统偏好",{"type":27,"tag":44,"props":1278,"children":1279},{},[1280],{"type":32,"value":1281},"提供手动切换选项",{"type":27,"tag":44,"props":1283,"children":1284},{},[1285],{"type":32,"value":1286},"确保足够的对比度",{"type":27,"tag":44,"props":1288,"children":1289},{},[1290],{"type":32,"value":1291},"优化图片和图表",{"type":27,"tag":44,"props":1293,"children":1294},{},[1295],{"type":32,"value":1296},"防止加载闪烁",{"type":27,"tag":28,"props":1298,"children":1299},{},[1300,1301,1305],{"type":32,"value":975},{"type":27,"tag":930,"props":1302,"children":1303},{},[1304],{"type":32,"value":980},{"type":32,"value":936},{"type":27,"tag":40,"props":1307,"children":1308},{},[1309,1314,1319,1324,1329],{"type":27,"tag":44,"props":1310,"children":1311},{},[1312],{"type":32,"value":1313},"强制单一模式",{"type":27,"tag":44,"props":1315,"children":1316},{},[1317],{"type":32,"value":1318},"忽视性能影响",{"type":27,"tag":44,"props":1320,"children":1321},{},[1322],{"type":32,"value":1323},"使用相同的颜色",{"type":27,"tag":44,"props":1325,"children":1326},{},[1327],{"type":32,"value":1328},"忘记保存用户偏好",{"type":27,"tag":44,"props":1330,"children":1331},{},[1332],{"type":32,"value":1333},"过度使用深色背景",{"type":27,"tag":128,"props":1335,"children":1336},{"id":1027},[1337],{"type":32,"value":1027},{"type":27,"tag":40,"props":1339,"children":1341},{"className":1340},[1033],[1342,1351,1360,1369,1378],{"type":27,"tag":44,"props":1343,"children":1345},{"className":1344},[1038],[1346,1349],{"type":27,"tag":1041,"props":1347,"children":1348},{"disabled":1043,"type":1044},[],{"type":32,"value":1350}," 在浅色和深色模式下测试所有页面",{"type":27,"tag":44,"props":1352,"children":1354},{"className":1353},[1038],[1355,1358],{"type":27,"tag":1041,"props":1356,"children":1357},{"disabled":1043,"type":1044},[],{"type":32,"value":1359}," 检查颜色对比度符合 WCAG 标准",{"type":27,"tag":44,"props":1361,"children":1363},{"className":1362},[1038],[1364,1367],{"type":27,"tag":1041,"props":1365,"children":1366},{"disabled":1043,"type":1044},[],{"type":32,"value":1368}," 验证图片和图表在两种模式下清晰",{"type":27,"tag":44,"props":1370,"children":1372},{"className":1371},[1038],[1373,1376],{"type":27,"tag":1041,"props":1374,"children":1375},{"disabled":1043,"type":1044},[],{"type":32,"value":1377}," 测试主题切换的平滑性",{"type":27,"tag":44,"props":1379,"children":1381},{"className":1380},[1038],[1382,1385],{"type":27,"tag":1041,"props":1383,"children":1384},{"disabled":1043,"type":1044},[],{"type":32,"value":1386}," 检查用户偏好是否被保存",{"title":7,"searchDepth":728,"depth":728,"links":1388},[1389,1390,1394,1399,1400,1401,1402,1403],{"id":1107,"depth":731,"text":1107},{"id":1129,"depth":731,"text":1129,"children":1391},[1392,1393],{"id":1134,"depth":728,"text":1137},{"id":1149,"depth":728,"text":1152},{"id":1164,"depth":731,"text":1164,"children":1395},[1396,1397,1398],{"id":1169,"depth":728,"text":1172},{"id":1184,"depth":728,"text":1187},{"id":1201,"depth":728,"text":1204},{"id":1216,"depth":731,"text":1216},{"id":1230,"depth":731,"text":1230},{"id":1244,"depth":731,"text":1244},{"id":921,"depth":731,"text":921},{"id":1027,"depth":731,"text":1027},"content:topics:design:dark-mode-design.md","topics/design/dark-mode-design.md","topics/design/dark-mode-design",{"_path":1408,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":1409,"description":1410,"keywords":1411,"image":1416,"author":1417,"date":757,"readingTime":1115,"topic":5,"body":1418,"_type":739,"_id":1683,"_source":741,"_file":1684,"_stem":1685,"_extension":744},"/topics/design/form-controls-design","表单控件设计规范","学习输入框、选择框、复选框等表单控件的设计和实现",[1412,1413,1414,1415,755],"表单设计","Form Controls","输入框","验证反馈","/images/topics/form-controls-design.jpg","AI Content Team",{"type":24,"children":1419,"toc":1669},[1420,1424,1429,1434,1439,1448,1453,1462,1466,1475,1480,1489,1494,1503,1508,1517,1522,1531,1535,1544,1570,1579,1607,1611],{"type":27,"tag":128,"props":1421,"children":1422},{"id":1409},[1423],{"type":32,"value":1409},{"type":27,"tag":28,"props":1425,"children":1426},{},[1427],{"type":32,"value":1428},"优秀的表单设计能够提高用户完成率和满意度。",{"type":27,"tag":128,"props":1430,"children":1432},{"id":1431},"输入框设计",[1433],{"type":32,"value":1431},{"type":27,"tag":776,"props":1435,"children":1437},{"id":1436},"基础文本输入",[1438],{"type":32,"value":1436},{"type":27,"tag":783,"props":1440,"children":1443},{"className":1441,"code":1442,"language":788,"meta":7},[786],".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",[1444],{"type":27,"tag":53,"props":1445,"children":1446},{"__ignoreMap":7},[1447],{"type":32,"value":1442},{"type":27,"tag":776,"props":1449,"children":1451},{"id":1450},"标签和提示",[1452],{"type":32,"value":1450},{"type":27,"tag":783,"props":1454,"children":1457},{"className":1455,"code":1456,"language":899,"meta":7},[897],"\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",[1458],{"type":27,"tag":53,"props":1459,"children":1460},{"__ignoreMap":7},[1461],{"type":32,"value":1456},{"type":27,"tag":128,"props":1463,"children":1464},{"id":1415},[1465],{"type":32,"value":1415},{"type":27,"tag":783,"props":1467,"children":1470},{"className":1468,"code":1469,"language":839,"meta":7},[837],"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",[1471],{"type":27,"tag":53,"props":1472,"children":1473},{"__ignoreMap":7},[1474],{"type":32,"value":1469},{"type":27,"tag":128,"props":1476,"children":1478},{"id":1477},"选择框设计",[1479],{"type":32,"value":1477},{"type":27,"tag":783,"props":1481,"children":1484},{"className":1482,"code":1483,"language":788,"meta":7},[786],".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",[1485],{"type":27,"tag":53,"props":1486,"children":1487},{"__ignoreMap":7},[1488],{"type":32,"value":1483},{"type":27,"tag":128,"props":1490,"children":1492},{"id":1491},"复选框和单选按钮",[1493],{"type":32,"value":1491},{"type":27,"tag":783,"props":1495,"children":1498},{"className":1496,"code":1497,"language":788,"meta":7},[786],".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",[1499],{"type":27,"tag":53,"props":1500,"children":1501},{"__ignoreMap":7},[1502],{"type":32,"value":1497},{"type":27,"tag":128,"props":1504,"children":1506},{"id":1505},"文本区域",[1507],{"type":32,"value":1505},{"type":27,"tag":783,"props":1509,"children":1512},{"className":1510,"code":1511,"language":788,"meta":7},[786],".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",[1513],{"type":27,"tag":53,"props":1514,"children":1515},{"__ignoreMap":7},[1516],{"type":32,"value":1511},{"type":27,"tag":128,"props":1518,"children":1520},{"id":1519},"完整表单示例",[1521],{"type":32,"value":1519},{"type":27,"tag":783,"props":1523,"children":1526},{"className":1524,"code":1525,"language":839,"meta":7},[837],"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",[1527],{"type":27,"tag":53,"props":1528,"children":1529},{"__ignoreMap":7},[1530],{"type":32,"value":1525},{"type":27,"tag":128,"props":1532,"children":1533},{"id":921},[1534],{"type":32,"value":921},{"type":27,"tag":28,"props":1536,"children":1537},{},[1538,1539,1543],{"type":32,"value":928},{"type":27,"tag":930,"props":1540,"children":1541},{},[1542],{"type":32,"value":934},{"type":32,"value":936},{"type":27,"tag":40,"props":1545,"children":1546},{},[1547,1552,1557,1562,1566],{"type":27,"tag":44,"props":1548,"children":1549},{},[1550],{"type":32,"value":1551},"使用正确的输入类型",{"type":27,"tag":44,"props":1553,"children":1554},{},[1555],{"type":32,"value":1556},"提供实时验证反馈",{"type":27,"tag":44,"props":1558,"children":1559},{},[1560],{"type":32,"value":1561},"清晰的标签和提示",{"type":27,"tag":44,"props":1563,"children":1564},{},[1565],{"type":32,"value":944},{"type":27,"tag":44,"props":1567,"children":1568},{},[1569],{"type":32,"value":970},{"type":27,"tag":28,"props":1571,"children":1572},{},[1573,1574,1578],{"type":32,"value":975},{"type":27,"tag":930,"props":1575,"children":1576},{},[1577],{"type":32,"value":980},{"type":32,"value":936},{"type":27,"tag":40,"props":1580,"children":1581},{},[1582,1587,1592,1597,1602],{"type":27,"tag":44,"props":1583,"children":1584},{},[1585],{"type":32,"value":1586},"隐藏标签",{"type":27,"tag":44,"props":1588,"children":1589},{},[1590],{"type":32,"value":1591},"过度使用占位符",{"type":27,"tag":44,"props":1593,"children":1594},{},[1595],{"type":32,"value":1596},"验证后立即提交",{"type":27,"tag":44,"props":1598,"children":1599},{},[1600],{"type":32,"value":1601},"忽视无障碍性",{"type":27,"tag":44,"props":1603,"children":1604},{},[1605],{"type":32,"value":1606},"复杂的验证规则",{"type":27,"tag":128,"props":1608,"children":1609},{"id":1027},[1610],{"type":32,"value":1027},{"type":27,"tag":40,"props":1612,"children":1614},{"className":1613},[1033],[1615,1624,1633,1642,1651,1660],{"type":27,"tag":44,"props":1616,"children":1618},{"className":1617},[1038],[1619,1622],{"type":27,"tag":1041,"props":1620,"children":1621},{"disabled":1043,"type":1044},[],{"type":32,"value":1623}," 所有控件都可用键盘导航",{"type":27,"tag":44,"props":1625,"children":1627},{"className":1626},[1038],[1628,1631],{"type":27,"tag":1041,"props":1629,"children":1630},{"disabled":1043,"type":1044},[],{"type":32,"value":1632}," 标签与输入框关联",{"type":27,"tag":44,"props":1634,"children":1636},{"className":1635},[1038],[1637,1640],{"type":27,"tag":1041,"props":1638,"children":1639},{"disabled":1043,"type":1044},[],{"type":32,"value":1641}," 验证消息清晰",{"type":27,"tag":44,"props":1643,"children":1645},{"className":1644},[1038],[1646,1649],{"type":27,"tag":1041,"props":1647,"children":1648},{"disabled":1043,"type":1044},[],{"type":32,"value":1650}," 色彩对比度足够",{"type":27,"tag":44,"props":1652,"children":1654},{"className":1653},[1038],[1655,1658],{"type":27,"tag":1041,"props":1656,"children":1657},{"disabled":1043,"type":1044},[],{"type":32,"value":1659}," 屏幕阅读器兼容",{"type":27,"tag":44,"props":1661,"children":1663},{"className":1662},[1038],[1664,1667],{"type":27,"tag":1041,"props":1665,"children":1666},{"disabled":1043,"type":1044},[],{"type":32,"value":1668}," 移动设备测试",{"title":7,"searchDepth":728,"depth":728,"links":1670},[1671,1672,1676,1677,1678,1679,1680,1681,1682],{"id":1409,"depth":731,"text":1409},{"id":1431,"depth":731,"text":1431,"children":1673},[1674,1675],{"id":1436,"depth":728,"text":1436},{"id":1450,"depth":728,"text":1450},{"id":1415,"depth":731,"text":1415},{"id":1477,"depth":731,"text":1477},{"id":1491,"depth":731,"text":1491},{"id":1505,"depth":731,"text":1505},{"id":1519,"depth":731,"text":1519},{"id":921,"depth":731,"text":921},{"id":1027,"depth":731,"text":1027},"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":1687,"image":18,"imageQuery":19,"pexelsPhotoId":20,"pexelsUrl":21,"featured":6,"readingTime":22,"body":1688,"_type":739,"_id":740,"_source":741,"_file":742,"_stem":743,"_extension":744},[13,14,15,16,17],{"type":24,"children":1689,"toc":2252},[1690,1694,1698,1740,1744,1763,1767,1771,1775,1859,1875,1879,1883,1887,1902,1906,1921,1925,1929,1933,1937,1952,1956,1977,1981,1996,2000,2004,2008,2061,2065,2069,2085,2112,2116,2131,2135,2150,2154,2158,2162,2177,2181,2185,2216,2220,2224,2228],{"type":27,"tag":28,"props":1691,"children":1692},{},[1693],{"type":32,"value":33},{"type":27,"tag":28,"props":1695,"children":1696},{},[1697],{"type":32,"value":38},{"type":27,"tag":40,"props":1699,"children":1700},{},[1701,1705,1732,1736],{"type":27,"tag":44,"props":1702,"children":1703},{},[1704],{"type":32,"value":48},{"type":27,"tag":44,"props":1706,"children":1707},{},[1708,1713,1714,1719,1720,1725,1726,1731],{"type":27,"tag":53,"props":1709,"children":1711},{"className":1710},[],[1712],{"type":32,"value":58},{"type":32,"value":60},{"type":27,"tag":53,"props":1715,"children":1717},{"className":1716},[],[1718],{"type":32,"value":66},{"type":32,"value":60},{"type":27,"tag":53,"props":1721,"children":1723},{"className":1722},[],[1724],{"type":32,"value":73},{"type":32,"value":60},{"type":27,"tag":53,"props":1727,"children":1729},{"className":1728},[],[1730],{"type":32,"value":80},{"type":32,"value":82},{"type":27,"tag":44,"props":1733,"children":1734},{},[1735],{"type":32,"value":87},{"type":27,"tag":44,"props":1737,"children":1738},{},[1739],{"type":32,"value":92},{"type":27,"tag":28,"props":1741,"children":1742},{},[1743],{"type":32,"value":97},{"type":27,"tag":28,"props":1745,"children":1746},{},[1747,1748,1752,1753,1757,1758,1762],{"type":32,"value":102},{"type":27,"tag":104,"props":1749,"children":1750},{"href":106},[1751],{"type":32,"value":109},{"type":32,"value":60},{"type":27,"tag":104,"props":1754,"children":1755},{"href":113},[1756],{"type":32,"value":116},{"type":32,"value":118},{"type":27,"tag":104,"props":1759,"children":1760},{"href":121},[1761],{"type":32,"value":124},{"type":32,"value":126},{"type":27,"tag":128,"props":1764,"children":1765},{"id":130},[1766],{"type":32,"value":133},{"type":27,"tag":28,"props":1768,"children":1769},{},[1770],{"type":32,"value":138},{"type":27,"tag":28,"props":1772,"children":1773},{},[1774],{"type":32,"value":143},{"type":27,"tag":145,"props":1776,"children":1777},{},[1778,1796],{"type":27,"tag":149,"props":1779,"children":1780},{},[1781],{"type":27,"tag":153,"props":1782,"children":1783},{},[1784,1788,1792],{"type":27,"tag":157,"props":1785,"children":1786},{},[1787],{"type":32,"value":161},{"type":27,"tag":157,"props":1789,"children":1790},{},[1791],{"type":32,"value":166},{"type":27,"tag":157,"props":1793,"children":1794},{},[1795],{"type":32,"value":171},{"type":27,"tag":173,"props":1797,"children":1798},{},[1799,1814,1829,1844],{"type":27,"tag":153,"props":1800,"children":1801},{},[1802,1806,1810],{"type":27,"tag":180,"props":1803,"children":1804},{},[1805],{"type":32,"value":184},{"type":27,"tag":180,"props":1807,"children":1808},{},[1809],{"type":32,"value":189},{"type":27,"tag":180,"props":1811,"children":1812},{},[1813],{"type":32,"value":194},{"type":27,"tag":153,"props":1815,"children":1816},{},[1817,1821,1825],{"type":27,"tag":180,"props":1818,"children":1819},{},[1820],{"type":32,"value":202},{"type":27,"tag":180,"props":1822,"children":1823},{},[1824],{"type":32,"value":207},{"type":27,"tag":180,"props":1826,"children":1827},{},[1828],{"type":32,"value":212},{"type":27,"tag":153,"props":1830,"children":1831},{},[1832,1836,1840],{"type":27,"tag":180,"props":1833,"children":1834},{},[1835],{"type":32,"value":80},{"type":27,"tag":180,"props":1837,"children":1838},{},[1839],{"type":32,"value":224},{"type":27,"tag":180,"props":1841,"children":1842},{},[1843],{"type":32,"value":229},{"type":27,"tag":153,"props":1845,"children":1846},{},[1847,1851,1855],{"type":27,"tag":180,"props":1848,"children":1849},{},[1850],{"type":32,"value":237},{"type":27,"tag":180,"props":1852,"children":1853},{},[1854],{"type":32,"value":242},{"type":27,"tag":180,"props":1856,"children":1857},{},[1858],{"type":32,"value":247},{"type":27,"tag":28,"props":1860,"children":1861},{},[1862,1863,1868,1869,1874],{"type":32,"value":252},{"type":27,"tag":53,"props":1864,"children":1866},{"className":1865},[],[1867],{"type":32,"value":73},{"type":32,"value":118},{"type":27,"tag":53,"props":1870,"children":1872},{"className":1871},[],[1873],{"type":32,"value":264},{"type":32,"value":266},{"type":27,"tag":128,"props":1876,"children":1877},{"id":269},[1878],{"type":32,"value":272},{"type":27,"tag":28,"props":1880,"children":1881},{},[1882],{"type":32,"value":277},{"type":27,"tag":28,"props":1884,"children":1885},{},[1886],{"type":32,"value":282},{"type":27,"tag":284,"props":1888,"children":1889},{},[1890,1894,1898],{"type":27,"tag":44,"props":1891,"children":1892},{},[1893],{"type":32,"value":291},{"type":27,"tag":44,"props":1895,"children":1896},{},[1897],{"type":32,"value":296},{"type":27,"tag":44,"props":1899,"children":1900},{},[1901],{"type":32,"value":301},{"type":27,"tag":28,"props":1903,"children":1904},{},[1905],{"type":32,"value":306},{"type":27,"tag":40,"props":1907,"children":1908},{},[1909,1913,1917],{"type":27,"tag":44,"props":1910,"children":1911},{},[1912],{"type":32,"value":314},{"type":27,"tag":44,"props":1914,"children":1915},{},[1916],{"type":32,"value":319},{"type":27,"tag":44,"props":1918,"children":1919},{},[1920],{"type":32,"value":324},{"type":27,"tag":28,"props":1922,"children":1923},{},[1924],{"type":32,"value":329},{"type":27,"tag":128,"props":1926,"children":1927},{"id":332},[1928],{"type":32,"value":335},{"type":27,"tag":28,"props":1930,"children":1931},{},[1932],{"type":32,"value":340},{"type":27,"tag":28,"props":1934,"children":1935},{},[1936],{"type":32,"value":345},{"type":27,"tag":40,"props":1938,"children":1939},{},[1940,1944,1948],{"type":27,"tag":44,"props":1941,"children":1942},{},[1943],{"type":32,"value":353},{"type":27,"tag":44,"props":1945,"children":1946},{},[1947],{"type":32,"value":358},{"type":27,"tag":44,"props":1949,"children":1950},{},[1951],{"type":32,"value":363},{"type":27,"tag":28,"props":1953,"children":1954},{},[1955],{"type":32,"value":368},{"type":27,"tag":40,"props":1957,"children":1958},{},[1959,1968],{"type":27,"tag":44,"props":1960,"children":1961},{},[1962,1963],{"type":32,"value":376},{"type":27,"tag":53,"props":1964,"children":1966},{"className":1965},[],[1967],{"type":32,"value":382},{"type":27,"tag":44,"props":1969,"children":1970},{},[1971,1972],{"type":32,"value":387},{"type":27,"tag":53,"props":1973,"children":1975},{"className":1974},[],[1976],{"type":32,"value":393},{"type":27,"tag":28,"props":1978,"children":1979},{},[1980],{"type":32,"value":398},{"type":27,"tag":40,"props":1982,"children":1983},{},[1984,1988,1992],{"type":27,"tag":44,"props":1985,"children":1986},{},[1987],{"type":32,"value":406},{"type":27,"tag":44,"props":1989,"children":1990},{},[1991],{"type":32,"value":411},{"type":27,"tag":44,"props":1993,"children":1994},{},[1995],{"type":32,"value":416},{"type":27,"tag":128,"props":1997,"children":1998},{"id":419},[1999],{"type":32,"value":422},{"type":27,"tag":28,"props":2001,"children":2002},{},[2003],{"type":32,"value":427},{"type":27,"tag":28,"props":2005,"children":2006},{},[2007],{"type":32,"value":432},{"type":27,"tag":145,"props":2009,"children":2010},{},[2011,2025],{"type":27,"tag":149,"props":2012,"children":2013},{},[2014],{"type":27,"tag":153,"props":2015,"children":2016},{},[2017,2021],{"type":27,"tag":157,"props":2018,"children":2019},{},[2020],{"type":32,"value":446},{"type":27,"tag":157,"props":2022,"children":2023},{},[2024],{"type":32,"value":451},{"type":27,"tag":173,"props":2026,"children":2027},{},[2028,2039,2050],{"type":27,"tag":153,"props":2029,"children":2030},{},[2031,2035],{"type":27,"tag":180,"props":2032,"children":2033},{},[2034],{"type":32,"value":462},{"type":27,"tag":180,"props":2036,"children":2037},{},[2038],{"type":32,"value":467},{"type":27,"tag":153,"props":2040,"children":2041},{},[2042,2046],{"type":27,"tag":180,"props":2043,"children":2044},{},[2045],{"type":32,"value":475},{"type":27,"tag":180,"props":2047,"children":2048},{},[2049],{"type":32,"value":480},{"type":27,"tag":153,"props":2051,"children":2052},{},[2053,2057],{"type":27,"tag":180,"props":2054,"children":2055},{},[2056],{"type":32,"value":488},{"type":27,"tag":180,"props":2058,"children":2059},{},[2060],{"type":32,"value":493},{"type":27,"tag":28,"props":2062,"children":2063},{},[2064],{"type":32,"value":498},{"type":27,"tag":128,"props":2066,"children":2067},{"id":501},[2068],{"type":32,"value":504},{"type":27,"tag":28,"props":2070,"children":2071},{},[2072,2073,2078,2079,2084],{"type":32,"value":509},{"type":27,"tag":53,"props":2074,"children":2076},{"className":2075},[],[2077],{"type":32,"value":515},{"type":32,"value":517},{"type":27,"tag":53,"props":2080,"children":2082},{"className":2081},[],[2083],{"type":32,"value":523},{"type":32,"value":525},{"type":27,"tag":40,"props":2086,"children":2087},{},[2088,2092,2096,2100,2104,2108],{"type":27,"tag":44,"props":2089,"children":2090},{},[2091],{"type":32,"value":533},{"type":27,"tag":44,"props":2093,"children":2094},{},[2095],{"type":32,"value":538},{"type":27,"tag":44,"props":2097,"children":2098},{},[2099],{"type":32,"value":543},{"type":27,"tag":44,"props":2101,"children":2102},{},[2103],{"type":32,"value":548},{"type":27,"tag":44,"props":2105,"children":2106},{},[2107],{"type":32,"value":553},{"type":27,"tag":44,"props":2109,"children":2110},{},[2111],{"type":32,"value":558},{"type":27,"tag":28,"props":2113,"children":2114},{},[2115],{"type":32,"value":563},{"type":27,"tag":40,"props":2117,"children":2118},{},[2119,2123,2127],{"type":27,"tag":44,"props":2120,"children":2121},{},[2122],{"type":32,"value":571},{"type":27,"tag":44,"props":2124,"children":2125},{},[2126],{"type":32,"value":576},{"type":27,"tag":44,"props":2128,"children":2129},{},[2130],{"type":32,"value":581},{"type":27,"tag":28,"props":2132,"children":2133},{},[2134],{"type":32,"value":586},{"type":27,"tag":40,"props":2136,"children":2137},{},[2138,2142,2146],{"type":27,"tag":44,"props":2139,"children":2140},{},[2141],{"type":32,"value":594},{"type":27,"tag":44,"props":2143,"children":2144},{},[2145],{"type":32,"value":599},{"type":27,"tag":44,"props":2147,"children":2148},{},[2149],{"type":32,"value":604},{"type":27,"tag":28,"props":2151,"children":2152},{},[2153],{"type":32,"value":609},{"type":27,"tag":128,"props":2155,"children":2156},{"id":612},[2157],{"type":32,"value":612},{"type":27,"tag":28,"props":2159,"children":2160},{},[2161],{"type":32,"value":619},{"type":27,"tag":40,"props":2163,"children":2164},{},[2165,2169,2173],{"type":27,"tag":44,"props":2166,"children":2167},{},[2168],{"type":32,"value":627},{"type":27,"tag":44,"props":2170,"children":2171},{},[2172],{"type":32,"value":632},{"type":27,"tag":44,"props":2174,"children":2175},{},[2176],{"type":32,"value":637},{"type":27,"tag":28,"props":2178,"children":2179},{},[2180],{"type":32,"value":642},{"type":27,"tag":128,"props":2182,"children":2183},{"id":645},[2184],{"type":32,"value":645},{"type":27,"tag":40,"props":2186,"children":2187},{},[2188,2192,2196,2200,2204,2208,2212],{"type":27,"tag":44,"props":2189,"children":2190},{},[2191],{"type":32,"value":655},{"type":27,"tag":44,"props":2193,"children":2194},{},[2195],{"type":32,"value":660},{"type":27,"tag":44,"props":2197,"children":2198},{},[2199],{"type":32,"value":665},{"type":27,"tag":44,"props":2201,"children":2202},{},[2203],{"type":32,"value":670},{"type":27,"tag":44,"props":2205,"children":2206},{},[2207],{"type":32,"value":675},{"type":27,"tag":44,"props":2209,"children":2210},{},[2211],{"type":32,"value":680},{"type":27,"tag":44,"props":2213,"children":2214},{},[2215],{"type":32,"value":685},{"type":27,"tag":128,"props":2217,"children":2218},{"id":688},[2219],{"type":32,"value":688},{"type":27,"tag":28,"props":2221,"children":2222},{},[2223],{"type":32,"value":695},{"type":27,"tag":28,"props":2225,"children":2226},{},[2227],{"type":32,"value":700},{"type":27,"tag":40,"props":2229,"children":2230},{},[2231,2238,2245],{"type":27,"tag":44,"props":2232,"children":2233},{},[2234],{"type":27,"tag":104,"props":2235,"children":2236},{"href":106},[2237],{"type":32,"value":109},{"type":27,"tag":44,"props":2239,"children":2240},{},[2241],{"type":27,"tag":104,"props":2242,"children":2243},{"href":113},[2244],{"type":32,"value":116},{"type":27,"tag":44,"props":2246,"children":2247},{},[2248],{"type":27,"tag":104,"props":2249,"children":2250},{"href":723},[2251],{"type":32,"value":726},{"title":7,"searchDepth":728,"depth":728,"links":2253},[2254,2255,2256,2257,2258,2259,2260,2261],{"id":130,"depth":731,"text":133},{"id":269,"depth":731,"text":272},{"id":332,"depth":731,"text":335},{"id":419,"depth":731,"text":422},{"id":501,"depth":731,"text":504},{"id":612,"depth":731,"text":612},{"id":645,"depth":731,"text":645},{"id":688,"depth":731,"text":688},1776174409937]