-_-\\ ...
标题很拗口,,而且JAVAEYE限制长度,, 不知道表述出本意没有,,
还原应用场景先:
以EXTJS教程中关于DD的示例代码为例子。
想通过DD,把A区域中的某个item拖放到B区域中,或者是B区域的子区域C中,B、C定义在同一个ddGroup中。定义代码如下:
dropTarget1 = new Tutorial.dd.MyDropTarget('dd2-B', {
ddGroup: 'group',
overClass: 'dd-over'
});
dropTarget2 = new Tutorial.dd.MyDropTarget('dd2-C', {
ddGroup: 'group',
overClass: 'dd-over'
});
把item拖放到B区域(父)中,no问题,示例代码中已经实现了。
把item拖放到C区域(子)中,问题来啦,notifyDrop方法被调用了2次!!
初步想法是,mouseup事件冒泡啦,C区域(子)响应后,再冒泡到B区域(父),DD的事件处理机制处理了两次drop。
再次测试 B的子区域多定义N个,重叠位置,notifyDrop方法则被调用N次...
跟踪代码,通过调用堆栈,定位到 DDCore.js中 Ext.dd.DragDropMgr 对象的 fireEvents方法。相关代码如下:
for (i in this.ids[sGroup]) {
var oDD = this.ids[sGroup][i];
if (! this.isTypeOfDD(oDD)) {
continue;
}
if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
if (this.isOverTarget(pt, oDD, this.mode)) {
// look for drop interactions
if (isDrop) {
dropEvts.push( oDD );
// look for drag enter and drag over interactions
} else {
// initial drag over: dragEnter fires
if (!oldOvers[oDD.id]) {
enterEvts.push( oDD );
// subsequent drag overs: dragOver fires
} else {
overEvts.push( oDD );
}
this.dragOvers[oDD.id] = oDD;
}
}
}
}
。。。
// fire drop events
for (i=0, len=dropEvts.length; i<len; ++i) {
dc.b4DragDrop(e, dropEvts[i].id);
dc.onDragDrop(e, dropEvts[i].id);
}
Ext 把group中定义的满足的target push 到dropEvts集合中,并循环调用 onDragDrop方法。 onDragDrop方法定义在DragSource.js文件中的Ext.dd.DragSource对象里。相关代码摘录如下:
/**
* An empty function by default, but provided so that you can perform a custom action before the dragged
* item is dragged out of the target without dropping, and optionally cancel the onDragOut.
* @param {Ext.dd.DragDrop} target The drop target
* @param {Event} e The event object
* @param {String} id The id of the dragged element
* @return {Boolean} isValid True if the drag event is valid, else false to cancel
*/
beforeDragOut : function(target, e, id){
return true;
},
// private
onDragDrop : function(e, id){
var target = this.cachedTarget || Ext.dd.DragDropMgr.getDDById(id);
if(this.beforeDragDrop(target, e, id) !== false){
if(target.isNotifyTarget){
if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
this.onValidDrop(target, e, id);
}else{
this.onInvalidDrop(target, e, id);
}
}else{
this.onValidDrop(target, e, id);
}
if(this.afterDragDrop){
/**
* An empty function by default, but provided so that you can perform a custom action
* after a valid drag drop has occurred by providing an implementation.
* @param {Ext.dd.DragDrop} target The drop target
* @param {Event} e The event object
* @param {String} id The id of the dropped element
* @method afterDragDrop
*/
this.afterDragDrop(target, e, id);
}
}
delete this.cachedTarget;
},
/**
* An empty function by default, but provided so that you can perform a custom action before the dragged
* item is dropped onto the target and optionally cancel the onDragDrop.
* @param {Ext.dd.DragDrop} target The drop target
* @param {Event} e The event object
* @param {String} id The id of the dragged element
* @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
*/
beforeDragDrop : function(target, e, id){
return true;
},
target.notifyDrop 这里即是EXTJS示例文件中notifyDrop调用的源头,这里beforeDragDrop方法是一个空方法,始终返回true。
分析入参发现,e是event对象,当前fireEvent的对象是C区域(子),ID是遍历前面DropEvts集合依次传入的target的ID,于是决定把判断加在这个方法中以屏蔽B区域(父)对当前事件的响应。代码如下:
Ext.dd.DragSource.prototype.beforeDragDrop = function(target, e, id){
if(e.getTarget().id == id)
return true;
else
return false;
}
----------------------------朴实的分割线----------------------------
在这种解决方案中,事件还是冒泡啦,只是通过判断dropEvts中的target是否是fireEvent的target而屏蔽notifyDrop方法的重复调用。
是否有更好的方式处理,希望达人不吝指教。
另,想重载Ext.dd.DargSource的beforeDragDrop方法时,发现这样做报错。。
Ext.extend(Ext.dd.DragSource,{
beforeDragDrop : function(target, e, id){
if(target.id==e.getTarget().id && target.id==id)
return true;
else
return false;
});
也希望达人不吝指教