欢迎各位兄弟 发布技术文章
这里的技术是共享的
事件是指一个特定的动做,这个动做能够针对HTML元素的,如keydown,keyup,mouseover, mouseout等,也能够是对于其它自定义的动做,如对Ajax异步请求的响应等。在ExtJS中,该如何处理呢?浏览器
1. 处理HTML元素的标准事件app
HTML元素的标准事件是指mouseover、mousedown、click、blur、focus、change等可以直接对HTML元素发生的事件。在ExtJS中,这些事件的处理能够用以下的代码:异步
注册一个事件处理函数使用: Ext.get('myElement').on('click', myHandler, myScope) myElement是要注册的元素的ID,click是事件的名称(注意,和HTML元素中的声明onide
XXX不一样,这里不须要on),myHandler 是处理函数的函数名称,myScope是一个可选的参数,指定处理函数绑定的对象,也就是处理函数的做用域,若是不提供这个参数,则是默认的 window。函数
撤销一个事件处理函数: Ext.get('myElement').un('click', myHandler, myScope) 参数的意义同上。ui
ExtJS会根据不一样的浏览器进行相应的处理,根本不须要理会用户用的是什么浏览器。根据事件的不一样,传给处理函数的参数也会不一样,这个只能参考ExtJS的文档了,必要时还得参考源代码。this
2. 处理自定义事件spa
在ExtJS中使用自定义事件,须要从Ext.util.Observable继承,示例代码以下:code
Employee = function(name){
this.name = name;
this.addEvents({
"fired" : true,
"quit" : true
});
}
Ext.extend(Employee, Ext.util.Observable, { ... });
在这段代码中,定义了一个Employee类,定义了fired和quit两个事件。如何触发这两个事件呢,基类Ext.util.Observable提供了触发自定义事件的方法fireEvent(eventName, arg1, arg2, ... argn), eventName是要触发的时间的名称(不区分大小写),后面的参数arg1,arg2等是要传给事件处理函数的参数。用上面的Employee类作示例,触发quit事件:component
this.fireEvent('quit', this);
这行代码将触发quit事件,并将Empolyee类的实例传给quit事件的处理函数,quit事件的订阅能够采用以下代码:
function myHandler1(empolyee){ ... }
function myHandler2(empolyee){ ... }
var emp = new Empolyee('tom');
emp.on('quit', myHandler1);
emp.on('quit', myHandler2);
在上面的代码中,为quit事件注册了两个处理函数(myHandler1与myHandler),当quit事件被激发时,将会依次调用myHandler1和myHandler2两个函数。
值得注意的是,无论是HTML元素的标准事件仍是自定义事件,若是为某个时间注册了多个处理函数,如前面的例子,若是myHandler1返回false 的话,则会取消在myHandler1以后注册的处理函数的执行,即该事件被取消,从而中止继续执行该事件的处理函数,而这个返回值false会做为事件 激发的结果,返回给empolyee,即:
var result = this.fireEvent('quit', this);
if (result === false) {
alert('event canceled'); //这里表示事件被某个处理函数取消
}
else {
alert('event complete'); // 这里表示事件执行完毕
}
经过Ext的自定义事件的机制,能够实现一对多的观察者模式,也能够实现一对一的绑定模式,这一点,在ExtJS的开发中是很重要的。
参考官方相关实现类:
/**
* @class Ext.calendar.form.EventWindow
* @extends Ext.Window
* <p>A custom window containing a basic edit form used for quick editing of events.</p>
* <p>This window also provides custom events specific to the calendar so that other calendar components can be easily
* notified when an event has been edited via this component.</p>
* @constructor
* @param {Object} config The config object
*/
Ext.define('Ext.calendar.form.EventWindow', {
extend: 'Ext.window.Window',
alias: 'widget.eventeditwindow',
requires: [
'Ext.form.Panel',
'Ext.calendar.util.Date',
'Ext.calendar.data.EventModel',
'Ext.calendar.data.EventMappings'
],
constructor: function(config) {
var formPanelCfg = {
xtype: 'form',
fieldDefaults: {
msgTarget: 'side',
labelWidth: 65
},
frame: false,
bodyStyle: 'background:transparent;padding:5px 10px 10px;',
bodyBorder: false,
border: false,
items: [{
itemId: 'title',
name: Ext.calendar.data.EventMappings.Title.name,
fieldLabel: 'Title',
xtype: 'textfield',
allowBlank: false,
emptyText: 'Event Title',
anchor: '100%'
},
{
xtype: 'daterangefield',
itemId: 'date-range',
name: 'dates',
anchor: '100%',
fieldLabel: 'When'
}]
};
if (config.calendarStore) {
this.calendarStore = config.calendarStore;
delete config.calendarStore;
formPanelCfg.items.push({
xtype: 'calendarpicker',
itemId: 'calendar',
name: Ext.calendar.data.EventMappings.CalendarId.name,
anchor: '100%',
store: this.calendarStore
});
}
this.callParent([Ext.apply({
titleTextAdd: 'Add Event',
titleTextEdit: 'Edit Event',
width: 600,
autocreate: true,
border: true,
closeAction: 'hide',
modal: false,
resizable: false,
buttonAlign: 'left',
savingMessage: 'Saving changes...',
deletingMessage: 'Deleting event...',
layout: 'fit',
defaultFocus: 'title',
onEsc: function(key, event) {
event.target.blur(); // Remove the focus to avoid doing the validity checks when the window is shown again.
this.onCancel();
},
fbar: [{
xtype: 'tbtext',
text: '<a href="#" id="tblink">Edit Details...</a>'
},
'->',
{
itemId: 'delete-btn',
text: 'Delete Event',
disabled: false,
handler: this.onDelete,
scope: this,
minWidth: 150,
hideMode: 'offsets'
},
{
text: 'Save',
disabled: false,
handler: this.onSave,
scope: this
},
{
text: 'Cancel',
disabled: false,
handler: this.onCancel,
scope: this
}],
items: formPanelCfg
},
config)]);
},
// private
newId: 10000,
// private
initComponent: function() {
this.callParent();
this.formPanel = this.items.items[0];
this.addEvents({
/**
* @event eventadd
* Fires after a new event is added
* @param {Ext.calendar.form.EventWindow} this
* @param {Ext.calendar.EventRecord} rec The new {@link Ext.calendar.EventRecord record} that was added
*/
eventadd: true,
/**
* @event eventupdate
* Fires after an existing event is updated
* @param {Ext.calendar.form.EventWindow} this
* @param {Ext.calendar.EventRecord} rec The new {@link Ext.calendar.EventRecord record} that was updated
*/
eventupdate: true,
/**
* @event eventdelete
* Fires after an event is deleted
* @param {Ext.calendar.form.EventWindow} this
* @param {Ext.calendar.EventRecord} rec The new {@link Ext.calendar.EventRecord record} that was deleted
*/
eventdelete: true,
/**
* @event eventcancel
* Fires after an event add/edit operation is canceled by the user and no store update took place
* @param {Ext.calendar.form.EventWindow} this
* @param {Ext.calendar.EventRecord} rec The new {@link Ext.calendar.EventRecord record} that was canceled
*/
eventcancel: true,
/**
* @event editdetails
* Fires when the user selects the option in this window to continue editing in the detailed edit form
* (by default, an instance of {@link Ext.calendar.EventEditForm}. Handling code should hide this window
* and transfer the current event record to the appropriate instance of the detailed form by showing it
* and calling {@link Ext.calendar.EventEditForm#loadRecord loadRecord}.
* @param {Ext.calendar.form.EventWindow} this
* @param {Ext.calendar.EventRecord} rec The {@link Ext.calendar.EventRecord record} that is currently being edited
*/
editdetails: true
});
},
// private
afterRender: function() {
this.callParent();
this.el.addCls('ext-cal-event-win');
Ext.get('tblink').on('click', this.onEditDetailsClick, this);
this.titleField = this.down('#title');
this.dateRangeField = this.down('#date-range');
this.calendarField = this.down('#calendar');
this.deleteButton = this.down('#delete-btn');
},
// private
onEditDetailsClick: function(e){
e.stopEvent();
this.updateRecord(this.activeRecord, true);
this.fireEvent('editdetails', this, this.activeRecord, this.animateTarget);
},
/**
* Shows the window, rendering it first if necessary, or activates it and brings it to front if hidden.
* @param {Ext.data.Record/Object} o Either a {@link Ext.data.Record} if showing the form
* for an existing event in edit mode, or a plain object containing a StartDate property (and
* optionally an EndDate property) for showing the form in add mode.
* @param {String/Element} animateTarget (optional) The target element or id from which the window should
* animate while opening (defaults to null with no animation)
* @return {Ext.Window} this
*/
show: function(o, animateTarget) {
// Work around the CSS day cell height hack needed for initial render in IE8/strict:
var me = this,
anim = (Ext.isIE8 && Ext.isStrict) ? null: animateTarget,
M = Ext.calendar.data.EventMappings;
this.callParent([anim, function(){
me.titleField.focus(true);
}]);
this.deleteButton[o.data && o.data[M.EventId.name] ? 'show': 'hide']();
var rec,
f = this.formPanel.form;
if (o.data) {
rec = o;
this.setTitle(rec.phantom ? this.titleTextAdd : this.titleTextEdit);
f.loadRecord(rec);
}
else {
this.setTitle(this.titleTextAdd);
var start = o[M.StartDate.name],
end = o[M.EndDate.name] || Ext.calendar.util.Date.add(start, {hours: 1});
rec = Ext.create('Ext.calendar.data.EventModel');
rec.data[M.StartDate.name] = start;
rec.data[M.EndDate.name] = end;
rec.data[M.IsAllDay.name] = !!o[M.IsAllDay.name] || start.getDate() != Ext.calendar.util.Date.add(end, {millis: 1}).getDate();
f.reset();
f.loadRecord(rec);
}
if (this.calendarStore) {
this.calendarField.setValue(rec.data[M.CalendarId.name]);
}
this.dateRangeField.setValue(rec.data);
this.activeRecord = rec;
return this;
},
// private
roundTime: function(dt, incr) {
incr = incr || 15;
var m = parseInt(dt.getMinutes(), 10);
return dt.add('mi', incr - (m % incr));
},
// private
onCancel: function() {
this.cleanup(true);
this.fireEvent('eventcancel', this);
},
// private
cleanup: function(hide) {
if (this.activeRecord && this.activeRecord.dirty) {
this.activeRecord.reject();
}
delete this.activeRecord;
if (hide === true) {
// Work around the CSS day cell height hack needed for initial render in IE8/strict:
//var anim = afterDelete || (Ext.isIE8 && Ext.isStrict) ? null : this.animateTarget;
this.hide();
}
},
// private
updateRecord: function(record, keepEditing) {
var fields = record.fields,
values = this.formPanel.getForm().getValues(),
name,
M = Ext.calendar.data.EventMappings,
obj = {};
fields.each(function(f) {
name = f.name;
if (name in values) {
obj[name] = values[name];
}
});
var dates = this.dateRangeField.getValue();
obj[M.StartDate.name] = dates[0];
obj[M.EndDate.name] = dates[1];
obj[M.IsAllDay.name] = dates[2];
record.beginEdit();
record.set(obj);
if (!keepEditing) {
record.endEdit();
}
return this;
},
// private
onSave: function(){
if(!this.formPanel.form.isValid()){
return;
}
if(!this.updateRecord(this.activeRecord)){
this.onCancel();
return;
}
this.fireEvent(this.activeRecord.phantom ? 'eventadd' : 'eventupdate', this, this.activeRecord, this.animateTarget);
// Clear phantom and modified states.
this.activeRecord.commit();
},
// private
onDelete: function(){
this.fireEvent('eventdelete', this, this.activeRecord, this.animateTarget);
}
});
来自 http://www.javashuo.com/article/p-eqxyrqsr-e.html