ExtJS v7中ViewController集成Ext.mixin.Observable报错求助
Ext.mixin.Observable时触发"Cannot read property 'listen' of undefined"错误 场景还原
你尝试给ViewController添加Ext.mixin.Observable混入,代码片段如下:
mixins: ['Ext.mixin.Observable'], constructor: function(config){ this.mixins.observable.constructor.call(this, config); }
但运行时却触发了如下错误栈:
ViewController BaseController.js?_dc=1587282588103:440 Uncaught TypeError: Cannot read property 'listen' of undefined at constructor.listen (BaseController.js?_dc=1587282588103:440) at constructor.callParent (Base.js?_dc=1587282588090:1479) at constructor.listen (ViewController.js?_dc=1587282588091:206) at constructor.updateListen (BaseController.js?_dc=1587282588103:257) at constructor.setter [as setListen] (Config.js?_dc=1587282588102:329) at Ext.Configurator.configure (Configurator.js?_dc=1587282588102:674) at constructor.initConfig (Base.js?_dc=1587282588090:1650) at constructor (Observable.js?_dc=1587282588091:437) at constructor (MainController.js?_dc=1587282588090:6)
你已经按照Sencha文档操作,想弄清楚问题根源在哪。
问题根源
核心原因是**Ext.app.ViewController本身就已经具备Observable的全部能力**,它的父类Ext.app.BaseController通过继承/混入的方式,已经实现了listen、on、fireEvent等所有Observable相关API。
你手动添加混入并调用Observable构造函数的操作,打乱了ViewController本身的初始化流程:ViewController在初始化时会优先处理listen配置,但此时混入的Observable还未完成正确的内部状态初始化,导致监听管理的核心对象未定义,最终抛出"Cannot read property 'listen' of undefined"错误。
解决方案
方案1:移除手动混入(推荐)
完全不需要额外添加mixins: ['Ext.mixin.Observable']配置,ViewController本身就支持Observable的所有功能。直接使用this.on()、this.fireEvent()、this.listen()这些方法即可,比如:
Ext.define('MyApp.controller.Main', { extend: 'Ext.app.ViewController', init: function() { // 直接使用监听方法 this.on('customEvent', this.handleCustomEvent, this); // 或者使用listen配置 this.listen({ controller: { '*': { someGlobalEvent: this.handleGlobalEvent } } }); }, handleCustomEvent: function() { // 处理事件 }, handleGlobalEvent: function() { // 处理全局事件 } });
方案2:若必须自定义混入(特殊场景)
如果你的业务场景确实需要自定义Observable混入(比如扩展Observable的能力),那么必须调整构造函数的执行顺序,先调用ViewController的父类构造函数,完成自身初始化后再调用混入的构造函数:
Ext.define('MyApp.controller.Custom', { extend: 'Ext.app.ViewController', mixins: ['Ext.mixin.Observable'], constructor: function(config) { // 先执行父类构造函数,完成ViewController的基础初始化 this.callParent([config]); // 再执行混入的Observable构造函数 this.mixins.observable.constructor.call(this, config); } });
但再次强调,99%的场景下方案1就足够了,因为ViewController原生就支持Observable特性。
内容的提问来源于stack exchange,提问作者ducktyped

