Layui select无原生open/close事件,只能通过监听.layui-form-select容器的layui-form-selected类增删或标题点击+document外部点击来近似捕获展开/收起行为,但无法100%精确对应真实面板显隐时机。

layui 下拉框没有原生的 open/close 事件
layui 的 select 渲染后是完全自定义 DOM(带 .layui-form-select 容器),它**不暴露下拉面板展开/收起的原生事件**,也没有 form.on('open(filter)') 或类似 API。所有官方文档和源码中均无 open、close、show、hide 等事件类型支持。
只能靠 class 变化 + click/mousedown 模拟监听
实际可操作的方式是监听渲染后下拉容器的 class 切换(layui-form-selected 类名的增删)或捕获用户点击行为,但需注意边界条件:
-
layui-form-selected类会在点击 select 标题区、点击箭头、甚至键盘Alt+↓时被添加;收起时(失焦、点击外部、回车确认)会被移除 - 直接给
.layui-form-select绑click会误触发(点标题是展开,点选项是选择,点空白是收起) - 用
document.addEventListener('click', ...)判断目标是否在下拉区域内外,性能差且易漏判(如 iframe、layer 弹窗内点击) - 不要监听
blur或focus—— layui 把焦点逻辑封装在内部,原始select元素始终处于display: none状态,无法可靠捕获
最实用的折中方案:监听点击标题 + 判断当前状态
如果你只需要“用户意图打开”和“用户明确收起”的粗略信号,可用以下模式:
form.on('select(status)', function(data) {
// 这里是选择发生后的回调,不是打开/关闭
});
// 单独监听标题点击(即用户点开下拉的动作)
$(document).on('click', '.layui-form-select span', function() {
const $selectWrap = $(this).closest('.layui-form-select');
const isOpen = $selectWrap.hasClass('layui-form-selected');
console.log(isOpen ? '已打开,本次是再次点击' : '用户点击标题,即将打开');
});
// 监听 document 点击,判断是否点在下拉区域外(近似“关闭”)
$(document).on('click', function(e) {
if (!$(e.target).closest('.layui-form-select').length) {
// 点击了下拉区域之外,大概率是收起了
// 但注意:这也会在表单其他地方点击时触发,需加防抖或过滤
}
});
这个方案不能 100% 精确对应“面板真正显示/隐藏”的时机,但覆盖了绝大多数人工操作路径。真正的 DOM 展开/收起由 layui 内部通过 addClass/removeClass('layui-form-selected') 控制,外部不可拦截。
为什么不要尝试 patch layui 源码或监听 MutationObserver
有人试图用 MutationObserver 监听 .layui-form-select 的 class 变化,但问题明显:
- layui 在展开前会先移除旧的
layui-form-selected(比如切换不同 select 时),造成「假关闭」 - 移动端 touch 事件、键盘导航、屏幕阅读器等场景下 class 变化节奏不一致
- layui 2.9.x 后部分版本改用
style.display控制子菜单显隐,不再依赖 class - 一旦 layui 升级,这类 hack 极易失效,且调试成本高
真正需要强感知开闭状态的场景(如自动聚焦、动画联动、无障碍支持),建议换用原生 select + CSS 自定义,或迁移到更现代的组件库(如 Element Plus、Ant Design Vue),layui 的设计初衷就不是为这类细粒度控制服务的。


















