解释 ExtJS4事件处理

我最近开始学习 ExtJS,并且在理解如何处理 Events 方面遇到了麻烦。我没有任何以前版本的 ExtJS 的经验。

通过阅读各种手册、指南和文档页面,我已经知道如何使用它,但我不清楚它是如何工作的。我找到了几个关于旧版本 ExtJS 的教程,但是我不确定它们在 ExtJS4中是否适用。

我特别关注的是“最后一句话”

  • 一个事件处理函数传递什么参数? 是否有一组标准的参数总是被传递?
  • 如何为我们编写的自定义组件定义自定义事件? 如何激发这些自定义事件?
  • 返回值(true/false)是否会影响事件泡沫的形成?如果没有,我们如何从事件处理程序内部或外部控制事件冒泡?
  • 是否有注册事件侦听器的标准方法?(到目前为止,我已经遇到了两种不同的方法,我不确定为什么每种方法都被使用)。

例如,这个问题使我相信事件处理程序可以接收相当多的参数。我看过其他一些教程,其中只有两个处理程序参数。什么改变?

107414 次浏览

让我们从描述 DOM 元素的事件处理开始。

DOM 节点事件处理

首先,您不希望直接使用 DOM 节点。相反,您可能希望利用 Ext.Element接口。为了分配事件处理程序,创建了 Element.addListenerElement.on(它们是等价的)。例如,如果我们有 html:

<div id="test_node"></div>

我们希望添加 click事件处理程序。
让我们恢复 Element:

var el = Ext.get('test_node');

现在让我们检查文档中的 click事件。它的处理程序可能有三个参数:

单击(Ext.EventObject e,HTMLElement t,Object eOpts)

了解所有这些我们可以分配处理程序的东西:

//       event name      event handler
el.on(    'click'        , function(e, t, eOpts){
// handling event here
});

Widgets 事件处理

Widgets 事件处理与 DOM 节点事件处理非常相似。

首先,小部件事件处理是通过利用 Ext.util.Observable混合实现的。为了正确地处理事件,您的小部件必须将 Ext.util.Observable作为混合文件包含在内。默认情况下,所有内置小部件(如 Panel、 Form、 Tree、 Grid 等)都有 Ext.util.Observable作为混合文件。

对于小部件,有两种分配处理程序的方法。第一种-是使用 开始方法(或 addListener)。例如,让我们创建 Button小部件并为其分配 click事件。首先,你应该检查事件文档中的处理程序参数:

单击(Ext.Button.Button this,Evente,ObjecteOpts)

现在让我们使用 on:

var myButton = Ext.create('Ext.button.Button', {
text: 'Test button'
});
myButton.on('click', function(btn, e, eOpts) {
// event handling here
console.log(btn, e, eOpts);
});

第二种方法是使用 widget 的 听众配置:

var myButton = Ext.create('Ext.button.Button', {
text: 'Test button',
listeners : {
click: function(btn, e, eOpts) {
// event handling here
console.log(btn, e, eOpts);
}
}
});

请注意,Button小部件是一种特殊的小部件。通过使用 handler配置,可以将 Click 事件分配给这个小部件:

var myButton = Ext.create('Ext.button.Button', {
text: 'Test button',
handler : function(btn, e, eOpts) {
// event handling here
console.log(btn, e, eOpts);
}
});

自定义事件触发

首先,您需要使用 AddEvents方法注册一个事件:

myButton.addEvents('myspecialevent1', 'myspecialevent2', 'myspecialevent3', /* ... */);

使用 addEvents方法是可选的。正如对此方法的注释所说,没有必要使用此方法,但它为事件文档提供了位置。

使用 FireEvent方法触发事件:

myButton.fireEvent('myspecialevent1', arg1, arg2, arg3, /* ... */);

arg1, arg2, arg3, /* ... */将传递给处理程序。现在我们可以处理您的事件:

myButton.on('myspecialevent1', function(arg1, arg2, arg3, /* ... */) {
// event handling here
console.log(arg1, arg2, arg3, /* ... */);
});

值得一提的是,在定义新小部件时,插入 AddEvents方法调用的最佳位置是小部件的 initComponent方法:

Ext.define('MyCustomButton', {
extend: 'Ext.button.Button',
// ... other configs,
initComponent: function(){
this.addEvents('myspecialevent1', 'myspecialevent2', 'myspecialevent3', /* ... */);
// ...
this.callParent(arguments);
}
});
var myButton = Ext.create('MyCustomButton', { /* configs */ });

防止事件冒泡

为了防止冒泡,您可以使用 return falseExt.EventObject.preventDefault()。为了防止浏览器的默认操作使用 Ext.EventObject.stopPropagation()

例如,让我们将 click 事件处理程序分配给我们的按钮。如果没有点击左键,则阻止默认浏览器操作:

myButton.on('click', function(btn, e){
if (e.button !== 0)
e.preventDefault();
});

启动应用程序范围内的事件

如何让控制者相互交流。

除了上面这个非常棒的答案之外,我还想提到应用程序范围内的事件,这些事件在 MVC 设置中非常有用,可以实现控制器之间的通信。(extjs4.1)

假设我们有一个带有选择框的控制器 Station (Sencha MVC 示例) :

Ext.define('Pandora.controller.Station', {
extend: 'Ext.app.Controller',
...


init: function() {
this.control({
'stationslist': {
selectionchange: this.onStationSelect
},
...
});
},


...


onStationSelect: function(selModel, selection) {
this.application.fireEvent('stationstart', selection[0]);
},
...
});

当选择框触发更改事件时,触发函数 onStationSelect

在这个函数中我们看到:

this.application.fireEvent('stationstart', selection[0]);

这将创建并激发一个应用程序范围的事件,我们可以从任何其他控制器侦听该事件。

因此,在另一个控制器中,我们现在可以知道何时更改了站点选择框。这是通过听取 this.application.on的意见完成的,具体如下:

Ext.define('Pandora.controller.Song', {
extend: 'Ext.app.Controller',
...
init: function() {
this.control({
'recentlyplayedscroller': {
selectionchange: this.onSongSelect
}
});


// Listen for an application wide event
this.application.on({
stationstart: this.onStationStart,
scope: this
});
},
....
onStationStart: function(station) {
console.info('I called to inform you that the Station controller select box just has been changed');
console.info('Now what do you want to do next?');
},
}

如果选择框已经更改,我们现在触发控制器 Song中的函数 onStationStart也..。

来自 Sencha 的文件:

应用程序事件对于具有许多控制器的事件非常有用。与在每个控制器中侦听相同的视图事件不同,只有一个控制器侦听视图事件并触发其他控制器可以侦听的应用程序范围的事件。这也允许控制器彼此之间进行通信,而不必知道或依赖于对方的存在。

在我的示例中: 单击一个树节点以更新网格面板中的数据。

感谢@gm2008在以下评论中提供的2016年最新信息:

在触发应用程序范围的自定义事件方面,在发布 ExtJS V5.1之后,现在有一种新的方法,即使用 Ext.GlobalEvents

触发事件时,可以调用: Ext.GlobalEvents.fireEvent('custom_event');

注册事件处理程序时,调用: Ext.GlobalEvents.on('custom_event', function(arguments){/* handler codes*/}, scope);

此方法不限于控制器。任何组件都可以通过将组件对象作为输入参数范围来处理自定义事件。

在 Sencha 文档中找到: MVC 第2部分

控制器事件侦听器的另一个技巧。

您可以使用通配符来监视来自任何组件的事件:

this.control({
'*':{
myCustomEvent: this.doSomething
}
});

还有两件事我觉得很有帮助,即使它们不是问题的一部分,真的。

您可以使用 relayEvents方法告诉一个组件侦听另一个组件的某些事件,然后再次激发它们,就好像它们来自第一个组件一样。API 文档给出了一个网格中继存储 load事件的示例。当编写封装多个子组件的自定义组件时,它非常方便。

反过来,也就是将封装组件 mycmp接收到的事件传递给它的子组件 subcmp,也可以这样做

mycmp.on('show' function (mycmp, eOpts)
{
mycmp.subcmp.fireEvent('show', mycmp.subcmp, eOpts);
});

我只是想在上面的精彩回答中再加几便士: 如果您正在使用 pre Extjs 4.1,并且没有应用程序范围的事件,但是需要它们,我一直在使用一个非常简单的技术,可能会有所帮助: 创建一个简单的对象扩展 Observer,并定义任何可能需要的应用程序范围的事件。然后,您可以从应用程序中的任何地方激发这些事件,包括实际的 html dom 元素,并通过从任何组件中继所需的元素来监听它们。

Ext.define('Lib.MessageBus', {
extend: 'Ext.util.Observable',


constructor: function() {
this.addEvents(
/*
* describe the event
*/
"eventname"


);
this.callParent(arguments);
}
});

然后你可以,从任何其他组成部分:

 this.relayEvents(MesageBus, ['event1', 'event2'])

并从任何组成部分或多姆元素发射它们:

 MessageBus.fireEvent('event1', somearg);


<input type="button onclick="MessageBus.fireEvent('event2', 'somearg')">