表单提交时值是否进请求体是判断后端收不到字段的唯一依据:disabled控件被完全过滤,readonly控件正常序列化;readonly仅对text/password/email/textarea生效,disabled则通用于所有表单元素。

表单提交时值会不会进请求体,是唯一不可妥协的判断依据
后端收不到字段?八成是把 readonly 写成了 disabled。这不是样式或体验问题,而是表单序列化行为的底层分水岭:disabled 的控件在 form.submit()、new FormData(form)、jQuery 的 .serialize() 中**直接被过滤掉**;readonly 的控件则照常参与序列化,后端能通过 request.getParameter("xxx") 或等价方式取到值。
常见翻车场景:
-
<input name="order_id" value="ORD-123" disabled>→ 提交后 request 里压根没有order_id字段 -
<input name="user_phone" value="138****1234" readonly>→ 用户能复制手机号,后端也能收到完整值
disabled 和 readonly 对不同表单元素的支持范围完全不同
readonly 只对 <input type="text">、<input type="password">、<input type="email">、<textarea></textarea> 生效;其他如 <select></select>、<input type="checkbox">、<button></button> 上写 readonly 属于无效代码,浏览器直接忽略。
disabled 则通吃全部:<select disabled></select>、<fieldset disabled></fieldset>(递归禁用子项)、<button disabled></button> 都合法且语义明确。
所以:
- 想让下拉框“只读”?别写
<select readonly></select>,要么换成<input type="text" readonly>模拟,要么 JS 控制每个<option disabled></option> - 批量禁用一组字段?用
<fieldset disabled></fieldset>,比逐个加disabled更可靠、更语义化
JavaScript 动态切换时,属性设置方式和副作用必须分清
设 disabled 很简单:el.disabled = true 或 el.disabled = false 即可,兼容性好、行为稳定。
设 readonly 要小心:el.readOnly = false 在部分旧版 Safari 下不触发重绘;稳妥做法是:el.setAttribute('readonly', '') 禁用,el.removeAttribute('readonly') 启用。
更重要的是副作用管理:
- 从编辑态切到
readonly:用户可能正聚焦该 input,此时它仍保持焦点但无法输入——建议手动调用el.blur()避免键盘操作卡住 - 切到
disabled:元素自动失焦,但下一个可聚焦元素可能不合理——需主动用el.nextElementSibling?.focus()引导焦点流 - 别同时写
readonly和disabled:后者优先级更高,前者形同虚设,还掩盖真实控制逻辑
视觉表现与无障碍支持不能靠默认样式凑合
disabled 输入框浏览器默认变灰(opacity: 0.6 或 color: #999),但 readonly 默认外观和普通 input 完全一致——如果希望用户一眼看出“不可改”,必须显式加 CSS,比如:
input[readonly] {
background-color: #f5f5f5;
cursor: not-allowed;
}
但这只是视觉提示,不改变行为;真正影响可访问性的,是焦点和屏幕阅读器播报:
-
disabled元素不会被屏幕阅读器读出(或读作“禁用”),且 Tab 键跳过 -
readonly元素会被正常读出,且支持focus事件监听——适合需要用户复制 API Key、订单号等关键文本的场景
最易被忽略的点:用键盘 Tab 导航走一遍表单流程,确认焦点不会卡在已切为 readonly 的字段上,也不会跳回刚设为 disabled 的按钮导致逻辑断裂。











