readonly 的值参与表单提交,disabled 的值被忽略;前者可聚焦、复制,后者不可交互且默认灰色;状态切换需兼顾焦点管理与无障碍支持。

readonly 和 disabled 看起来一样,但表单提交时行为完全不同
很多人以为 readonly 和 disabled 都是“不让用户改”,但它们在表单提交、焦点、样式响应上差异极大。关键区别在于:readonly 元素的值会随表单一起提交,disabled 的则完全被忽略——哪怕 DOM 里还挂着那个 input,后端根本收不到它的值。
-
readonly:可聚焦、可选中、可复制(Ctrl+C)、值参与序列化(form.submit()或new FormData(form)都包含它) -
disabled:不能聚焦、不能选中、不能复制、值不参与任何表单提交,且默认灰色(opacity: 0.6或color: #999,取决于浏览器) - 两者都阻止键盘输入,但
disabled还会禁用鼠标事件(如click),而readonly不会
状态机里该用哪个?取决于你是否需要保留字段语义和值
比如一个订单详情页,用户不能改收货地址,但后端必须收到这个地址用于发货——这时必须用 readonly。如果这个字段只是展示用(比如“下单时间”),压根不需要传给后端,或者它属于流程控制字段(如“审批状态”由系统自动写入,用户连看都不该看),那就用 disabled 更干净。
- 要保留字段名+值 → 用
readonly,配合 CSS 覆盖默认样式(如background: #f5f5f5)避免看起来像可编辑 - 要彻底隔离字段(不参与提交、不占交互焦点、视觉上明确不可用)→ 用
disabled - 别在同一个字段上同时设
readonly="true"和disabled="true"——disabled优先级更高,readonly直接失效
JavaScript 动态切换时容易漏掉 focus 状态和键盘陷阱
用 JS 控制状态机时,光改属性不够。比如从编辑态切到只读态,用户可能正聚焦在那个 input 上,此时它变成 readonly 后仍保持焦点,但按 Tab 键会跳过它(因为不是 disabled);而切到 disabled 态时,它会自动失焦,但若之前有焦点,屏幕阅读器可能卡住或跳转异常。
- 切换为
readonly前,建议手动调用element.blur()避免焦点残留 - 切换为
disabled后,检查下一个可聚焦元素是否合理(可用element.nextElementSibling?.focus()引导) - 别依赖
tabindex="-1"来“隐藏”焦点——它不能替代disabled的语义,且对屏幕阅读器支持不一致 - 测试时用键盘 Tab 导航走一遍流程,确认焦点流不中断、不跳回已禁用字段
React/Vue 等框架里绑定属性要小心布尔值陷阱
框架模板中写 :disabled="isLocked" 没问题,但若写成 :readonly="isReadOnly",注意 Vue 2 默认把 readonly 当作 prop(非原生属性),需加 .prop 修饰符;React 中 readOnly 是驼峰写法,拼错就无效。
- Vue:用
:readonly.prop="true"或v-bind:readonly.prop="isReadOnly",否则绑定失败 - React:必须是
readOnly={true}(不是readonly),JSX 里大小写敏感 - Svelte:直接
readonly={isReadOnly}即可,但首次渲染时若isReadOnly为undefined,可能被忽略——显式初始化为false更稳 - 所有框架下,避免用字符串
"readonly"或"disabled"当布尔值,它们会被当真值处理(即等价于true)
disabled 字段在 FormData 中彻底消失,而 readonly 字段即使灰掉也照常提交——这点一旦出错,后端要么收不到关键数据,要么收到脏数据。

















