不能直接当步骤条用,因其仅提供静态序号语义,无状态控制、校验联动或dom切换能力,硬套会导致可访问性失效、逻辑断裂及后端校验脱节。

别用 <ol></ol> 做多步骤注册流程——它只负责编号语义,不提供状态控制、校验联动或 DOM 切换能力,硬套会导致可访问性失效、逻辑断裂、后端校验脱节。
为什么 <ol></ol> 不能直接当步骤条用
HTML 有序列表 <ol></ol> 的本质是「带序号的语义化容器」,浏览器和屏幕阅读器只把它当作静态内容流处理。它没有内置的 currentStep 状态、无法响应字段校验结果、也不能控制 <section></section> 显隐。常见错误是:把每步塞进 <li>,再用 CSS 隐藏非当前项——但 aria-hidden="true" 和 tabindex="-1" 必须加在 <section></section> 上,不是 <li>;否则键盘焦点仍会落入隐藏区域,屏幕阅读器照读不误。
更关键的是:用户点击“第三步”按钮时,<ol></ol> 不会阻止跳转,也不会校验前两步是否通过。你得额外写 JS 绑定事件、拦截行为、维护状态——那还不如一开始就用语义更清晰的结构。
真正该用的 HTML 结构组合
步骤条视觉层可用 <ol></ol>(仅限展示),但整个流程必须由外层容器 + 步骤容器 + 状态变量协同驱动:
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
- 外层用
<div class="wizard"> 包住全部逻辑,不依赖表单原生提交 <li>步骤条用 <code><ol class="steps"></ol>,每个<li data-step="1">仅作视觉映射,不承载交互 - 每步内容用独立
<section data-step="1" aria-hidden="false"></section>,显隐靠 JS 切换aria-hidden和tabindex - 所有按钮统一用
type="button",仅最后一步的提交按钮保留type="submit"并配event.preventDefault() - 定义
validateStep1():只检查email字段是否符合required和type="email",不碰密码字段 - 定义
validateStep2():只校验password和confirm_password是否匹配、长度是否 ≥8 - 切换前调用
if (currentStep === 1 && validateStep1()) { updateStep(2); },updateStep()函数负责更新data-step类、aria-hidden和焦点管理 - 前端每次切换步骤,向后端发轻量请求(如
POST /api/step?step=2),后端记录 session 中的step_completed = [1] - 最终提交时,后端检查
step_completed是否包含所有前置步骤(如要求 [1,2] 都存在才接受注册) - 不要信任前端传来的
currentStep值,它只是 UI 提示;后端以 session 或 JWT 中的步骤标记为准
currentStep 怎么和校验函数绑定
核心是「校验先行,状态后置」:每次点击按钮,先运行对应步骤的校验函数,只在校验返回 true 时才更新 currentStep 并切换 DOM 状态。不能把校验逻辑写在按钮 onclick 里,必须集中管理:
漏掉这层校验拦截,用户就能跳过邮箱验证直接进第二步——步骤条显示“已完成”,实际数据根本无效。
前后端防护怎么避免绕过
前端 JS 可被禁用或 DOM 被手动修改,所以后端必须校验请求中携带的步骤上下文:
最容易被忽略的是:很多人只在前端做 disabled 按钮,却没在后端验证上一步是否真实完成——攻击者删掉 disabled 属性、改 DOM、甚至直接 curl 提交,就能跳过中间校验。










