解释ExtJS 4事件处理


130

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

通过阅读各种手册,指南和文档页面,我已经弄清楚了如何使用它,但是我不清楚它是如何工作的。我已经找到了一些针对旧版ExtJS的教程,但不确定它们在ExtJS 4中的适用性。

我正在专门研究诸如此类的“最后一句话”

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

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


2
刚刚注意到...主题不对?
jrharshath 2014年

12
在该问题上有88票赞成,在第一个答案上有155票赞成,伟大而强大的安德鲁认为这是不重要的。严重的断电继续!
boatcoder

3
我投票决定重新开始这个问题,因为这里的答案是金矿。我已经编辑了问题,使其更适合问与答风格。
dbrin

1
请再次打开此问题,因为这确实是有帮助的真实问题。所以我们不能盲目地关闭它。
Piyush Dholariya 2015年

2
这是一个措辞得当的问题,我认为没有理由予以解决。取消这个主题很可笑。投票要求重新开放。
Mike Fuchs

Answers:


222

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

DOM节点事件处理

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

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

我们想要添加click事件处理程序。
让我们检索Element

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

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

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.Observablemixin 实现小部件事件处理。为了正确处理事件,您的小部件必须包含Ext.util.Observable一个mixin。Ext.util.Observable默认情况下,所有内置小部件(如Panel,Form,Tree,Grid,...)都具有mixin。

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

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

现在使用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);
});

第二种方法是使用小部件的侦听器配置:

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小部件是一种特殊的小部件。可以使用handlerconfig 将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 false使用或使用Ext.EventObject.preventDefault()。为了防止浏览器的默认操作,请使用Ext.EventObject.stopPropagation()

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

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

3
这个,很贪婪,但是有什么办法可以通过一些配置来做“ addEvents”吗?:)
jrharshath's

@jrharshath,据我所知,不幸的是,没有办法通过config来做到这一点。
分子人》

如何创建这些文件-'myspecialevent1',我看到您已经附加并处理了它,但是我们如何创建这些文件?
heyNow 2012年

1
辉煌的答案!我是ExtJs的新手,正在寻找一种引用页面中任何元素并在其上使用事件处理程序的方法,就像jQuery。你教我!谢谢!
Rutwick Gangurde 2014年

1
“防止事件冒泡”部分中的小错误。stopPropagation用于防止事件冒泡,preventDefault用于防止默认行为/操作。
MatRt 2014年

44

引发应用范围的事件

如何使控制器互相交谈...

除了上述非常好的答案之外,我还要提及应用程序范围的事件,这些事件在MVC设置中启用控制器之间的通信非常有用。(extjs4.1)

假设我们有一个带有选择框的控制器站(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?');
    },
}

如果选择框已更改,我们现在也将onStationStart在控制器中触发该功能Song...

从Sencha文档:

应用程序事件对于具有许多控制器的事件非常有用。代替在每个这些控制器中侦听相同的视图事件,只有一个控制器侦听该视图事件并触发一个应用程序范围的事件,其他控制器可以侦听该事件。这也允许控制器之间相互通信,而无需了解或依赖彼此的存在。

就我而言:单击树节点以更新网格面板中的数据。

感谢@ gm2008,来自以下评论,更新2016:

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

触发事件时,您可以致电: Ext.GlobalEvents.fireEvent('custom_event');

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

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

在Sencha Docs中找到:MVC第2部分


1
关于触发应用程序范围内的自定义事件,在ExtJS V5.1发布之后,现在有一个新方法,即使用Ext.GlobalEvents。当您触发事件时,您调用。Ext.GlobalEvents.fireEvent('custom_event');当您注册事件的处理程序时,您将调用Ext.GlobalEvents.on('custom_event', function(arguments){/* handler codes*/}, scope};这里是小提琴。该方法不限于控制器。通过将组件对象作为输入参数,任何组件都可以处理自定义事件scope。这个问题应该重新开始。
gm2008年

15

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

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

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

12

只是想在上面的出色答案中添加几分:如果您正在使用Extjs 4.1之前的版本,并且没有应用程序级事件,但是需要它们,我一直在使用一种非常简单的技术,该技术可能会有所帮助:创建一个扩展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')">

仅供参考,从EXT JS 5.0开始不推荐使用this.addEvents。因此,现在无需添加事件
Ajay Sharma

11

我发现只有两件事对我有所帮助,即使它们确实不是问题的一部分。

您可以使用该relayEvents方法告诉组件侦听另一个组件的某些事件,然后再次触发它们,就好像它们源自第一个组件一样。API文档提供了一个中继商店load事件的网格示例。在编写封装了几个子组件的自定义组件时,这非常方便。

相反,也可以像这样将封装组件接收的事件传递mycmp给子组件之一subcmp

mycmp.on('show' function (mycmp, eOpts)
{
   mycmp.subcmp.fireEvent('show', mycmp.subcmp, eOpts);
});
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.