【问题标题】:Explain ExtJS 4 event handling解释 ExtJS 4 事件处理
【发布时间】:2011-11-07 18:38:11
【问题描述】:

我最近开始学习 ExtJS,但无法理解如何处理事件。我没有任何以前版本的 ExtJS 的经验。

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

我特别关注诸如此类的“最终决定”

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

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

【问题讨论】:

  • 刚刚注意到...跑题了?
  • 88 人赞成这个问题,155 人赞成第一个答案,伟大而强大的安德鲁认为这个问题离题了。正在进行严重的电力旅行!
  • 我已经投票决定重新提出这个问题,因为这里的答案是一座金矿。我已经编辑了问题以更好地适应 Q 和 A 风格。
  • 请再次打开此问题,因为它真的很有帮助且真实。所以我们不能盲目地关闭它。
  • 这是一个措辞恰当的问题,我认为没有理由关闭它。把这个话题称为题外话是荒谬的。投票支持重新开放。

标签: javascript extjs event-handling extjs4


【解决方案1】:

让我们从描述 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 事件处理与 DOM 节点事件处理非常相似。

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

对于小部件,有两种分配处理程序的方法。第一个 - 是使用on 方法(或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);
});

第二种方式是使用widget的listeners配置:

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 config 分配给这个小部件:

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 方法是可选的。正如此方法的 cmets 所说,不需要使用此方法,但它为事件文档提供了位置。

要触发您的事件,请使用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()

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

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

【讨论】:

  • 这是贪婪,但是有没有办法通过一些配置来做“addEvents”的事情? :)
  • @jrharshath,据我所知,不幸的是,没有办法通过配置来做到这一点。
  • 如何创建这些 -'myspecialevent1',我看到您已附加并处理了它,但我们如何创建这些?
  • 绝妙的答案!我是 ExtJs 的新手,正在寻找一种方法来引用页面中的任何元素并在它们上使用事件处理程序,就像 jQuery 一样。你教我的!谢谢!
  • “防止事件冒泡”部分中的小错误。 stopPropagation 用于防止事件冒泡,preventDefault 用于防止默认行为/动作。
【解决方案2】:

触发应用程序范围的事件

如何让控制器相互通信...

除了上面非常棒的答案之外,我还想提一下应用程序范围的事件,这些事件在 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]);
    },    
   ...
});

When the select box triggers a change event, the function onStationSelect is fired.

在该函数中我们看到:

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 文档:

应用程序事件对于有很多控制器的事件非常有用。不是在每个控制器中监听相同的视图事件,而是只有一个控制器监听视图事件并触发其他可以监听的应用程序范围的事件。这也允许控制器在不知道或依赖于彼此存在的情况下相互通信。

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

感谢以下 cmets 的 @gm2008 更新 2016:

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

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

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

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

Found in Sencha Docs: MVC Part 2

【讨论】:

  • ExtJS V5.1发布后,在触发应用程序范围的自定义事件方面,现在有一个新方法,即使用Ext.GlobalEvents。当您触发事件时,您调用Ext.GlobalEvents.fireEvent('custom_event'); 当您注册事件的处理程序时,您调用Ext.GlobalEvents.on('custom_event', function(arguments){/* handler codes*/}, scope}; 这是一个fiddle。此方法不限于控制器。任何组件都可以通过将组件对象作为输入参数scope来处理自定义事件。应该重新提出问题。
【解决方案3】:

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

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

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

【讨论】:

    【解决方案4】:

    只是想在上面的优秀答案中添加几便士: 如果您正在使用 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')">
    

    【讨论】:

    • 仅供参考,this.addEvents 从 EXT JS 5.0 开始已被弃用。所以现在不需要添加事件
    【解决方案5】:

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

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

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

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

    【讨论】:

      猜你喜欢
      • 2011-08-30
      • 1970-01-01
      • 2013-11-03
      • 2012-01-08
      • 1970-01-01
      • 2012-07-11
      • 1970-01-01
      • 2012-01-16
      • 2014-06-29
      相关资源
      最近更新 更多