实际上,您的代码中至少存在四个明显不同的问题:
- 类内方法调用的范围处理
- 组件创建效率低下
- 控制器中的组件事件处理
- 控制器间通信
范围处理
第一个问题可以通过使用闭包或将范围参数传递给 Ajax 请求来解决,如上面@kevhender 所描述的。鉴于此,我建议编写更清晰的代码:
controllerMethodOne: function() {
Ext.Ajax.request({
url: ...,
params: ...,
scope: this,
success: this.onMethodOneSuccess,
failure: this.onMethodOneFailure
});
},
// `this` scope is the controller here
onMethodOneSuccess: function(response) {
...
},
// Same scope here, the controller itself
onMethodOneFailure: function(response) {
...
}
组件创建
创建菜单项的方式效率较低,因为every菜单项将被创建并一一渲染到 DOM。这也几乎没有必要:您预先拥有项目列表并且您可以控制,因此让我们保持代码的美观和声明性,并一次性创建所有菜单项:
// I'd advocate being a bit defensive here and not trust the input
// Also, I don't see the `list` var declaration in your code,
// do you really want to make it a global?
var list, items;
list = Ext.JSON.decode(response.responseText);
items = Ext.Array.map(list, function(item) {
return {
xtype: 'menuitem',
text: item.text
}
});
// Another global? Take a look at the refs section in Controllers doc
storeMenu.add(items);
这里的变化是我们正在迭代list
并创建即将出现的菜单项声明的新数组。然后我们一次性添加它们,节省大量重新渲染和重新布局的资源storeMenu
.
组件事件处理
当这个函数所做的只是调用控制器时,在每个菜单项上设置一个处理函数是完全没有必要的,而且效率很低。当单击菜单项时,它会触发click
事件 - 您所需要做的就是连接控制器以侦听这些事件:
// Suppose that your storeMenu was created like this
storeMenu = new Ext.menu.Menu({
itemId: 'storeMenu',
...
});
// Controller's init() method will provide the wiring
Ext.define('MyController', {
extend: 'Ext.app.Controller',
init: function() {
this.control({
// This ComponentQuery selector will match menu items
// that descend (belong) to a component with itemId 'storeMenu'
'#storeMenu menuitem': {
click: this.controllerMethodTwo
}
});
},
// The scope is automatically set to the controller itself
controllerMethodTwo: function(item) {
...
}
});
一种最佳实践是尽可能细粒度地编写 ComponentQuery 选择器,因为它们是全局的,如果您不够精确,您的控制器方法可能会捕获来自不需要的组件的事件。
控制器间通信
目前这可能有点牵强,但既然您使用的是 Ext JS 4.2,您不妨利用我们在这方面添加的改进。在 4.2 之前,有一种首选(也是唯一)的方法从另一个控制器调用一个控制器的方法:
Ext.define('My.controller.Foo', {
extend: 'Ext.app.Controller',
methodFoo: function() {
// Need to call controller Bar here, what do we do?
this.getController('Bar').methodBar();
}
});
Ext.define('My.controller.Bar', {
extend: 'Ext.app.Controller',
methodBar: function() {
// This method is called directly by Foo
}
});
在 Ext JS 4.2 中,我们添加了事件域的概念。这意味着现在控制器不仅可以监听组件的事件,还可以监听其他实体的事件。包括自己的控制器域:
Ext.define('My.controller.Foo', {
extend: 'Ext.app.Controller',
methodFoo: function() {
// Effectively the same thing as above,
// but no direct method calling now
this.fireEvent('controllerBarMethodBar');
}
});
Ext.define('My.controller.Bar', {
extend: 'Ext.app.Controller',
// Need some wiring
init: function() {
this.listen({
controller: {
'*': {
controllerBarMethodBar: this.methodBar
}
}
});
},
methodBar: function() {
// This method is called *indirectly*
}
});
这可能看起来是一种更复杂的做事方式,但实际上在大型应用程序中使用它要简单得多,并且它解决了我们遇到的主要问题:控制器之间不再需要硬绑定,您可以单独测试每个控制器。
请参阅我的博客文章中的更多内容:Ext JS 4.2 中的控制器事件 http://nohuhu.org/development/controller-events-in-ext-js-4-2/