解释ExtJS 4事件处理

我最近开始学习ExtJS,并且很难理解如何处理事件。 我没有任何以前版本的ExtJS的经验。

从阅读各种手册,指南和文档页面,我已经想出了如何使用它,但我不清楚它是如何工作的。 我已经find了几个老版本的ExtJS教程,但我不确定它们在ExtJS 4中的适用性。

我特别关注诸如此类的“最后一句话”

  • 事件处理函数传递了什么参数? 是否有一组标准的总是通过?
  • 如何为我们编写的自定义组件定义自定义事件? 我们如何才能解决这些自定义事件?
  • 返回值(true / false)是否影响事件如何起泡? 如果没有,我们如何控制事件处理程序内部或外部的事件冒泡?
  • 有没有注册事件监听器的标准方法? (到目前为止,我已经遇到了两种不同的方式,但我不确定每种方法的用法)。

例如, 这个问题使我相信一个事件处理程序可以收到不less的论据。 我见过其他教程,只有两个参数的处理程序。 什么改变?

首先描述DOM元素的事件处理。

DOM节点事件处理

首先你不想直接使用DOM节点。 相反,你可能会想利用Ext.Element接口。 为了分配事件处理程序,创build了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 }); 

小部件事件处理

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

首先,小部件的事件处理是通过利用Ext.util.Observable mixin来实现的。 为了正确处理事件,你的小部件必须包含Ext.util.Observable作为一个混合。 所有内置的小部件(如面板,窗体,树,网格等)都将Ext.util.Observable默认为混合。

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

点击(Ext.button.Button this,Event e,Object eOpts)

现在让我们使用:

 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); }); 

第二种方法是使用小部件的监听器configuration:

 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小部件是一种特殊的小部件。 点击事件可以通过使用handlerconfiguration分配给这个小部件:

 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 false或使用Ext.EventObject.preventDefault() 。 为了防止浏览器的默认操作使用Ext.EventObject.stopPropagation()

例如,让我们将点击事件处理程序分配给我们的button。 如果不是左键被点击,防止默认的浏览器操作:

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

发射应用程序广泛的事件

如何让控制器相互交谈

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

比方说我们有一个控制器站(Sencha MVC的例子)与一个select框:

 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]); }, ... }); 

当select框触发更改事件时,将onStationSelectfunction。

在这个函数中我们看到:

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

这创build并触发了我们可以从任何其他控制器收听的应用程序事件。

因此,在另一个控制器中,我们现在可以知道何时站select框已经改变。 这是通过听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?'); }, } 

如果select框已经被改变,我们现在在控制器的Song onStationStart上的function…

从Sencha文档:

应用程序事件对于具有多个控制器的事件非常有用。 与其在每个控制器中侦听相同的视图事件,只有一个控制器侦听视图事件并触发其他人可以侦听的应用程序范围的事件。 这也允许pipe制员彼此沟通而不知道彼此的存在或取决于彼此的存在。

在我的情况下:单击树节点来更新网格面板中的数据。

更新2016年感谢@ gm2008从下面的评论:

就射击应用程序范围内的自定义事件而言,在ExtJS V5.1发布后,现在有一种新的方法,它使用了Ext.GlobalEvents

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

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

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

在Sencha文档中find:MVC第2部分

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

您可以使用通配符从任何组件观察事件:

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

只是想添加几个便士上面的优秀答案:如果你正在工作的Extjs 4.1,并没有应用程序范围的事件,但需要他们,我一直在使用一个非常简单的技术,可能会有所帮助:创build一个简单的对象扩展Observable,并定义您可能需要的任何应用程序范围的事件。 然后,您可以从应用程序的任何位置(包括实际的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']) 

并从任何组件或dom元素中解雇他们:

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

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

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

另一种方式, mycmp由封装组件mycmp接收的事件传递给其子组件subcmp ,可以像这样完成

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