在基于 ExtJS 4.2 进行项目开发时,不少开发者会遇到一个令人困扰的问题:Ext.grid.plugin.RowExpander 插件虽然在文档中明确列出了 collapsebody 和 expandbody 事件,但实际绑定后却始终无法触发。翻遍社区帖子、尝试各种重写 init 和 toggleRow 的方法,依然无济于事。问题究竟出在哪里?又该如何有效解决?
问题根源:源码中根本未定义这两个事件
直接查阅 Ext.grid.plugin.RowExpander 的源代码可以清楚看到,该插件本身并没有声明 collapsebody 和 expandbody 事件。即便按照网络流传的方式重写 init 和 toggleRow 方法,也无法真正让它们生效——因为事件从未被正确地挂载到对应的对象上。
解决方案:让 Grid 对象自行承担事件触发职责
既然插件自身没有提供事件接口,那就主动为 Grid 对象添加这两个事件。核心思路如下:
- 在 Grid 的配置中直接定义
listeners,监听expandbody和collapsebody; - 重写
Ext.grid.plugin.RowExpander的toggleRow方法,在展开或折叠时手动触发 Grid 上的这两个事件。
这样做的好处在于——既保留了插件的全部原有功能,又能确保事件回调正常运作,而且代码改动量极小。
具体实现步骤与完整测试代码
下面是一份可直接运行的测试代码,关键改动已用注释标注。请特别注意 Ext.override 中对 toggleRow 的改写,以及最后 Grid 配置中的 listeners 部分。
ExtJS 4.2 RowExpander 无法触发 collapsebody、expandbody 事件的完美解决方案

代码的核心改动就在 toggleRow 方法的最后一行——不再通过 view 触发事件,而是改为 this.grid.fireEvent(...)。同时,在 init 中已为 Grid 对象添加了 collapsebody 和 expandbody 事件。这样一来,在 Grid 配置中定义的 listeners.expandbody 就能正常工作了。
几点注意事项:
- 不要再用插件自身的
listeners去定义这两个事件,因为插件本身并不具备这两个事件; - 如果使用了锁定列(lockable)模式,上述代码中已做了兼容处理,确保两个视图能同步状态;
- 该方案在 ExtJS 4.2.1 及更高版本上测试通过,更低版本可能需要适当微调。
解决了这个痛点,后续开发中就能更自由地利用行展开/折叠的回调来执行数据加载、样式切换等操作。希望这份代码能帮你节省大量调试时间。
