必须直接在原生标签写disabled属性并调layui.form.render('select')才有效,因layui仅识别原生disabled行为(置灰、禁交互、不提交),忽略lay-data、css样式及js伪禁用;动态禁用需先设option.disabled再统一render;键盘操作需手动拦截;服务端须预渲染disabled属性,ajax更新后需同步状态。

必须直接在原生 <option></option> 标签上写 disabled 布尔属性,再调 layui.form.render('select'),其他任何方式都无效。
为什么不能用 lay-data 或 JS 设样式?
Layui 的 select 是隐藏原生 <select></select>、用伪 DOM(<dl></dl>)模拟下拉面板。它完全不读取 lay-data 里的字段,也不响应你给 <dd></dd> 加的 layui-disabled 类或 opacity: 0.5 样式。禁用逻辑只认原生 disabled 属性——浏览器原生行为:置灰、鼠标不可点、键盘跳过、提交时自动忽略该值。
常见错误包括:
-
<option value="2" lay-data='{"disabled":true}'>上海</option>→ 完全没效果 -
$(option).css('opacity', 0.5)→ 看起来灰了,但依然能点、能键盘选中、能提交 -
$(option).attr('disabled', 'false')→disabled是布尔属性,写任何字符串值("false"、"0")都等同于true
动态禁用某项的正确操作步骤
比如要禁用 value="2" 的选项,且表单 filter 是 "myForm":
- 先定位并设置原生
<option></option>的disabled属性:document.querySelector('select[name="city"] option[value="2"]').disabled = true; - 再调渲染:
layui.form.render('select', 'myForm');—— 注意必须传'select'类型,否则默认只刷 checkbox/radio - IE11 下
querySelector可能不稳定,建议 fallback:Array.from(selectEl.options).find(opt => opt.value === '2').disabled = true; - 批量禁用多个选项时,**不要在循环里反复调
form.render('select')**,先统一设好所有option.disabled,最后只调一次render
键盘操作仍能选中禁用项?得手动拦截
Layui 没监听 disabled 状态做键盘校验。↑↓ 键焦点仍会停在禁用项上,按回车照样触发 form.on('select()')。这不是 UI 问题,是逻辑漏洞。
临时补救方案是在事件回调开头加守卫:
layui.form.on('select(city)', function(data) {
const $opt = $(data.elem).find(`option[value="${data.value}"]`);
if ($opt.prop('disabled')) {
data.elem.value = ''; // 清空选择
layui.form.render('select', 'myForm');
return;
}
// 后续业务逻辑...
});
更稳妥的做法是,在 form.on('select()') 之外,额外绑定 keydown 并阻止禁用状态下的方向键和回车:
$(data.elem).on('keydown', function(e) {
if ($(this).is(':disabled') && [13, 38, 40].includes(e.keyCode)) {
e.preventDefault();
}
});
服务端预渲染和数据同步最容易被忽略
如果禁用逻辑依赖后端权限字段(如 isAvailable: false),必须确保:
- Thymeleaf/Vue 模板在首次输出 HTML 时,就已把
disabled写进对应<option></option>;否则用户打开页面第一眼就能绕过 - AJAX 更新数据后,若禁用状态变化,不仅要改
option.disabled,还要同步更新本地缓存或数据源,否则翻页、刷新后禁用失效 - 禁用不是“一劳永逸”的开关:鼠标点击、键盘导航、初始加载、JS 动态修改——这四个环节少一个,用户就能绕过去











