首页 文章

解释ExtJS 4事件处理

提问于
浏览
123

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

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

我特别关注像这样的“最后一句话”

  • 事件处理函数传递了什么参数?是否有一套标准的args总能通过?

  • 如何为我们编写的自定义组件定义自定义事件?我们如何解雇这些自定义事件?

  • 返回值(true / false)会影响事件的泡沫吗?如果没有,我们如何控制事件处理程序内部或外部的事件冒泡?

  • 有注册事件监听器的标准方法吗? (我've come across two different ways til now, and I'我不确定为什么使用每种方法) .

例如,this question让我相信事件处理程序可以接收相当多的参数 . 我见过其他教程,只有两个参数处理器 . 有什么变化?

5 回答

  • 12

    让我们从描述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
    });
    

    小部件事件处理

    窗口小部件事件处理与DOM节点事件处理非常相似 .

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

    对于小部件,有两种分配处理程序的方法 . 第一个 - 是使用on方法(或 addListener ) . 我们举个例子创建 Button 小部件并为其分配 click 事件 . 首先你应该检查事件's docs for handler'的参数:

    点击(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 widget是一种特殊的小部件 . 可以使用handler config将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();
    });
    
  • 11

    解雇应用程序范围的事件

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

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

    From the Sencha docs:

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

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

    Update 2016 thanks to @gm2008 from the comments below:

    在激发应用程序范围的自定义事件方面,在发布 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

  • 217

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

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

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

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

    我发现有两件事有助于了解,即使它们不是问题的一部分,真的 .

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

    反过来,即将封装组件 mycmp 收到的事件传递给它的一个子组件 subcmp ,可以像这样完成

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

相关问题