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