Объясните обработку событий ExtJS 4

Недавно я начал изучать ExtJS и не понимаю, как обрабатывать события. У меня нет опыта предыдущих версий ExtJS.

Из чтения различных руководств, руководств и страниц документации я выяснил, как их использовать, но я не понимаю, как это работает. Я нашел несколько руководств для более старых версий ExtJS, но я не уверен, насколько они применимы в ExtJS 4.

Я специально смотрю "последнее слово" на такие вещи, как

  • Какие аргументы передаются функции обработки событий? Есть ли стандартный набор аргументов, которые всегда передаются?
  • Как определить пользовательские события для настраиваемых компонентов, которые мы пишем? как мы можем запустить это пользовательское событие?
  • влияет ли возвращаемое значение (true/false) на то, как событие пузырится? Если нет, как мы можем управлять пузырьками событий изнутри или за пределами обработчика событий?
  • Есть ли стандартный способ регистрации прослушивателей событий? (Я сталкивался с двумя разными способами до сих пор, и я не уверен, почему каждый метод использовался).

Например, этот вопрос заставляет меня думать, что обработчик событий может получить немало аргументов. Я видел другие учебники, в которых для обработчика всего два аргумента. Какие изменения?

Ответ 1

Давайте начнем с описания обработки событий элементов DOM.

DOM node обработка событий

Прежде всего, вы не захотите напрямую работать с DOM node. Вместо этого вы, вероятно, захотите использовать Ext.Element интерфейс. Для назначения обработчиков событий Element.addListener и Element.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
});

Обработка событий Widgets

Обработка событий Widgets в значительной степени похожа на обработку событий узлов DOM.

Прежде всего, обработка событий виджетов реализуется с помощью 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, событие e, объект 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);
});

Второй способ - использовать виджет listeners config:

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 - это особый вид виджетов. Событие Click можно присвоить этому виджету, используя 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 является необязательным. Поскольку комментарии к этому методу говорят, что нет необходимости использовать этот метод, но он предоставляет место для документации по событиям.

Чтобы запустить ваше мероприятие 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 является метод widget 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();
});

Ответ 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]);
    },    
   ...
});

Когда поле выбора запускает событие изменения, запускается функция 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:

События приложений чрезвычайно полезны для событий, которые имеют много контроллеров. Вместо того, чтобы слушать одно и то же событие просмотра в каждом из этих контроллеров, только один контроллер прослушивает событие просмотра и запускает событие приложения, которое другие могут прослушивать. Это также позволяет контроллерам общаться друг с другом, не зная о существовании или в зависимости от существования других.

В моем случае: щелкнуть по дереву node для обновления данных на панели сетки.

Обновление 2016 благодаря @gm2008 из комментариев ниже:

С точки зрения обмана пользовательских событий в приложении, теперь появляется новый метод после публикации ExtJS V5.1, который использует Ext.GlobalEvents.

Когда вы запускаете события, вы можете вызвать: Ext.GlobalEvents.fireEvent('custom_event');

Когда вы регистрируете обработчик события, вы вызываете: Ext.GlobalEvents.on('custom_event', function(arguments){/* handler codes*/}, scope};

Этот метод не ограничивается контроллерами. Любой компонент может обрабатывать настраиваемое событие, помещая объект компонента в качестве области входных параметров.

Найдено в Sencha Docs: MVC Part 2

Ответ 3

Еще один трюк для прослушивателей событий контроллера.

Вы можете использовать подстановочные знаки для наблюдения за событием из любого компонента:

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

Ответ 4

Просто хотел добавить пару пенсов к превосходным ответам выше: Если вы работаете над 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')">

Ответ 5

Еще две вещи, которые я нашел полезными, даже если они не являются частью вопроса, действительно.

Вы можете использовать метод relayEvents, чтобы сообщить компоненту прослушивать определенные события другого компонента, а затем запускать их снова, как если бы они исходили из первого компонента. В документах API представлен пример сетки, передающей событие store load. Это очень удобно при написании пользовательских компонентов, которые инкапсулируют несколько подкомпонентов.

Другой способ: передача событий, полученных инкапсулирующим компонентом mycmp в один из его подкомпонентов subcmp, может быть выполнена следующим образом:

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