`

Ext drag 那些事

阅读更多
//panel初始化拖拽函数
initDraggable : function() {
        if (this.simpleDrag) {// default value is 'false'
            this.initSimpleDraggable();
        }
    else {
           this.dd = new Ext.panel.DD(this, Ext.isBoolean(this.draggable) ? null : this.draggable);
}

在EXT有一个Ext-dd-DragDropManager类(理解浏览器的事件传播模型很重要), 该类在初始化的第一件事就是在docment上注册
mousemove 如下:
Ext.define('Ext.dd.DragDropManager', {
    singleton: true,
。。。。。。。
}, function() {
this._addListeners();
})

_addListeners: function() {
        if ( document ) {
//初始化拖拽相关的事件(如下)
            this._onLoad();
        } else {
    //确保document.body已加载完毕
            if (this._timeoutCount <= 2000) {
                setTimeout(this._addListeners, 10);
                if (document && document.body) {
                    this._timeoutCount += 1;
                }
            }
        }
    },
_onLoad: function() {
this.init();
var Event = Ext.EventManager;
        Event.on(document, "mouseup",   this.handleMouseUp, this, true);
//当我们在document拖动鼠标时,会触发handleMouseMove函数,这里需要提醒的一点是: 在实际处理cmp的拖动
//事件时,是有限制的,例如拖动范围必须大于某个值(可佩的),才会触发, 具体的拖拽函数并不是实时执行的,而是利用
//setTimeOut(drageFn, 1000(可佩的))
        Event.on(document, "mousemove", this.handleMouseMove, this, true);
        Event.on(window,   "unload",    this._onUnload, this, true);
        Event.on(window,   "resize",    this._onResize, this, true);
        // Event.on(window,   "mouseout",    this._test);

    }

Ext-dd-DragDropManager是一个单例模式,负责处理所有cmp控件的拖拽,Ext-dd-DragDropManager中有一个属性dragCurrent是用来
记录当前的拖拽对象,当退拽事件发生时,会通过dragCurrent.onDrag等类似的方式,来传递所有的与拖拽相关的事件处理机制

//接下来我们来具体看一下Ext.panel.Panel的拖拽初始化(从Ext.panel.DD说起)
1. Ext.panel.DD.constructor
var me = this;
    me.panel = panel;
me.dragData = {panel: panel};
//下面这行代码的含义是: 建议打开ext文档的portal demo例子看一下,当拖拽时会出现两种现象,1.出现一个虚线框(样式
//是可以自定义的),2.当前拖动的panel好像没有了item,只是一个panel的框架, 当我们松开鼠标时,panel又恢复了。
//所以我要说的这两种现象的处理都在new Ext.panel.Proxy实现的,第一种现象是proxy(虚线框),第二种现象是ghost,panel的
//复制版本,他与当前的panel的关系是:
     *constructor: function(panel, config){
* var me = this;
* me.panel = panel;
* me.id = me.panel.id +'-ddproxy';
* Ext.apply(me, config);
*}
*当我们开始拖拽的时候,他会调用Ext.panel.Proxy.show方法, 看一下show方法的源码,我们就明白了
me.panelProxy = new Ext.panel.Proxy(panel, cfg);
me.proxy = me.panelProxy.proxy;
me.callParent([panel.el, cfg]);
//还记得当拖拽panel的时候,我们的鼠标会变成"move"形状, 在Ext当中,当我们把鼠标放在某个cmp上时,如果出现move形状,
//那么这个cmp叫做"handlerEl", 知道这个东东,ok那我们就可以任意指定panel移动时的handlerEL了(扩展Ext.panel.DD),默认情况下是panel.header.el
//如果你的panel的header是false,那么此时的handler就是panel.body了, 没错,me.setupEl(panel)方法就是干这个事情(详细代码如下)
me.setupEl(panel);
2. Ext.panel.DD.setupEl
    setupEl: function(panel){
        var me = this,
            header = panel.header,
//默认是panel.body
            el = panel.body;
           
        if (header) {//如果有header,那就是header.el
            me.setHandleElId(header.id);
            el = header.el;
        }
        if (el) {
//惊呆了,原来如此
            el.setStyle('cursor', 'move');
            me.scroll = false;
        } else {
          panel.on('boxready', me.setupEl, me, {single: true});
        }
},
 
  //关于该构造函数参数是什么意思,看一下他的子类Ext.panel.DD:
     *  me.callParent([panel.el, cfg]);
*
*
3.Ext.dd.DragSource.constructor(Ext.panel.DD的父类)
//el就是当前panel的el,说白了就是当前panel的dom
    this.el = Ext.get(el);
//this.dragData, 该属性,在拖拽事件函数中可以拿到这个值
if(!this.dragData){
  this.dragData = {};
}
Ext.apply(this, config);
if(!this.proxy){
     //还记得上面提到proxy吗? 他就是那个虚线框,其实默认就是this.proxy
this.proxy = new Ext.dd.StatusProxy({
  id: this.el.id + '-drag-status-proxy',
  //指定是否在Repair的时候添加me.el.animate特效(更加线性)
  animRepair: this.animRepair
});
}
//调用父类构造(在下面介绍)
this.callParent([this.el.dom, this.ddGroup || this.group,
{dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true}]);
//状态标识
this.dragging = false;

4.Ext.dd.DDProxy.constructor(Ext.dd.DragSource的父类)
     if (id) {
        //在父类Ext.dd.DragDrop(在下面介绍)
*在dd中group有何作用,我的理解是在同一group下的cmp target是支持互相drop的
*而这些group与cmp都是存储在Ext.dd.DragDropManager中的ids属性当中

}
    this.init(id, sGroup, config);
//见5.xxxxx.createFrame
            this.initFrame();

//在document.body的body.firstChild前面插入一个div元素
*  <div id="${panel.el.id}-drag-status-proxy" style="position:absolute; visibility: hidden; cursor:move; border: 2px solid #aaa; zIndex: 999">
*  </div>
*
5.Ext.dd.DDProxy.createFrame
       var self = this,
body = document.body,
div,
s;

if (!body || !body.firstChild) {
setTimeout( function() { self.createFrame(); }, 50 );
return;
}

//Ext.dd.DragDrop.getDragEl 其实就是获取proxy.dom
div = this.getDragEl();
                   
//div不为空,因为proxy是已经存在的
if (!div) {
div    = document.createElement("div");
//就是this.el.id + '-drag-status-proxy'(还记得这样代码吗?)
div.id = this.dragElId;
s  = div.style;

s.position   = "absolute";
s.visibility = "hidden";
s.cursor     = "move";
s.border     = "2px solid #aaa";
s.zIndex     = 999;
body.insertBefore(div, body.firstChild);
}

6.Ext.dd.DragDrop.init
        //从方法名称,我可以得出target这个术语,每次在Ext的DD机制当中,target是其组成的一个部分,那么他的作用是什么的
//加入 我想将一个panel移动到另一panel当中。 首先目标panel必须的是一个target,当拖拽事件over在目标target上时,
//此时target就可以接受当前的proxy,
* 这id就是panel.el.dom(它不是proxy.dom哦)
*
this.initTarget(id, sGroup, config);
//监控dom of this.id的 mousedown事件(见下面handleMouseDown)
Ext.EventManager.on(this.id, "mousedown", this.handleMouseDown, this);

6.Ext.dd.DragDrop.initTarget
    initTarget: function(id, sGroup, config) {
        // configuration attributes
        this.config = config || {};
//Ext.dd.DragDropManager这个东东,在开始的时候我有介绍它在EXT DD机制中所扮演的角色
        this.DDMInstance = Ext.dd.DragDropManager;
       this.groups = {};
if (typeof id !== "string") {
            id = Ext.id(id);
    }
this.id = id;
//还记得我之前说过的target吗? 他在dd中扮演的角色,以及角色是如何被创建的, ok addToGroup就是做这件事情的
//最终所有的target都会存放在Ext.dd.DragDropManager(我是单例的哦)的属性当中
this.addToGroup((sGroup) ? sGroup : "default");
//还记得我之前介绍的handler吗?
this.handleElId = id;
//设置一个默认的DragElId
this.setDragElId(id);
this.invalidHandleTypes = { A: "A" };
        this.invalidHandleIds = {};
        this.invalidHandleClasses = [];
//这个方法是在
this.applyConfig();
this.handleOnAvailable();
    },
7.Ext.dd.DragDrop.applyConfig(Ext.dd.DDProxy已经复写)
applyConfig: function() {

        // configurable properties:
        //    padding, isTarget, maintainOffset, primaryButtonOnly
        this.padding           = this.config.padding || [0, 0, 0, 0]; //padding
        this.isTarget          = (this.config.isTarget !== false); // is target
        this.maintainOffset    = (this.config.maintainOffset); //null
        this.primaryButtonOnly = (this.config.primaryButtonOnly !== false); //true

}
8.Ext.dd.DDProxy.applyConfig
    this.callParent();
this.resizeFrame = (this.config.resizeFrame !== false); //false
this.centerFrame = (this.config.centerFrame); //false
this.setDragElId(this.config.dragElId || Ext.dd.DDProxy.dragElId); //proxy.id

//该方法是panel drag事件的真正起始处理入口
9.Ext.dd.DragDrop.handleMouseDown
var me = this;
//可以通过指定primaryButtonOnly=true,来保证当鼠标点击icon button不会触发drag
if ((me.primaryButtonOnly && e.button != 0) || me.isLocked()) {
return;
}
//重置当前所有的dd对象的位置信息
me.DDMInstance.refreshCache(me.groups);
//me.DDMInstance.isOverTarget方法是判断当前鼠标的位置是否在 me 的之上(over)
if (me.hasOuterHandles || me.DDMInstance.isOverTarget(e.getPoint(), me))  {
if (me.clickValidator(e)) {
// set the initial element position
me.setStartPosition();
me.b4MouseDown(e);
me.onMouseDown(e);
//接下来就是将当前的me传给dragCurrent ,之后的mousemove事件就可以开始了
me.DDMInstance.handleMouseDown(e, me);
   me.DDMInstance.stopEvent(e);
}
}

10.Ext.dd.DragDropManager.handleMouseDown
handleMouseDown: function(e, oDD) {
        var me = this,
            el;

        if (Ext.quickTipsActive){
            Ext.tip.QuickTipManager.ddDisable();
        }
        if (me.dragCurrent){
            me.handleMouseUp(e);
        }

        me.currentTarget = e.getTarget();
        me.dragCurrent = oDD;// 就是他,接下来了我们看看dragCurrent是怎么被使用的

        el = oDD.getEl();
if (Ext.isIE9m && el.setCapture) {
            el.setCapture();
        }

        // track start position
        me.startX = e.getPageX();
        me.startY = e.getPageY();

        me.deltaX = me.startX - el.offsetLeft;
        me.deltaY = me.startY - el.offsetTop;

        me.dragThreshMet = false;

        me.clickTimeout = setTimeout(
            function() {
//clickTimeThresh(默认350毫秒之后,也就是说,当你按住鼠标350毫秒之后就会发生情况)毫秒之后会执行函数startDrag
//(见如下分析)
   me.startDrag(me.startX, me.startY);
            },
            me.clickTimeThresh
        );
    }
//---------------------------------------------接下来的分析就是鼠标down的时候所发生的事情------------------------------------------

//在这个方法里current 就是我们上一个方法注入的dragCurrent
11.Ext.dd.DragDropManager.startDrag
   startDrag: function(x, y) {
        var me = this,
            current = me.dragCurrent,
            dragEl;

        clearTimeout(me.clickTimeout);
        if (current) {
//就是Ext.panel.DD中的b4StartDrag方法(见如下分析)
            current.b4StartDrag(x, y);
//需要自己实现,默认情况下Ext.panel.DD为Ext.emptyFn
            current.startDrag(x, y);
//见14分析。获取克隆panel的EL
            dragEl = current.getDragEl();

            // Add current drag class to dragged element
            if (dragEl) {
//给克隆panel加上一些样式,该样式可以在Ext.panel.DD的属性中定义
                Ext.fly(dragEl).addCls(me.dragCls);
            }
        }
        me.dragThreshMet = true;
    },

12.Ext.panel.DD.b4StartDrag
//还记的那个proxy吗?在Ext.panel.DD的构造函数里有这么一行代码:
//me.panelProxy = new Ext.panel.Proxy(panel, cfg)
   b4StartDrag: function(x, y) {
//见如下代码分析
        this.panelProxy.show();
    }

13.Ext.panel.Proxy.show
   show: function(){
        var me = this,
            panelSize;
           
        if (!me.ghost) {
            panelSize = me.panel.getSize();
            me.panel.el.setVisibilityMode(Ext.Element.DISPLAY);
//显示一个克隆 panel
            me.ghost = me.panel.ghost();
            if (me.insertProxy) {
                //在me.panel.dom的before位置插入一个DIV,(默认情况下是一个虚线框)
me.proxy = me.panel.el.insertSibling({cls: Ext.baseCSSPrefix + 'panel-dd-spacer'});
                me.proxy.setSize(panelSize);
            }
        }
    }

14. Ext.panel.DD.getDragEl
//具体克隆panel的处理在Ext.panel.Panel.ghost()
getDragEl : function(e){
        var ghost = this.panelProxy.ghost;
        if (ghost) {
            return ghost.el.dom;
        }
    }

//---------------------------------------------接下来的分析就是鼠标move的时候所发生的事情------------------------------------------
//该方法是drag move事件的入口处理函数
15. Ext.dd.DragDropManager.handleMouseMove
    handleMouseMove: function(e) {
        var me = this,
            current = me.dragCurrent,
            diffX,
            diffY;

        if (!current) {
            return true;
        }
//dragThreshMet默认为false
        if (!me.dragThreshMet) {
            diffX = Math.abs(me.startX - e.getPageX());
            diffY = Math.abs(me.startY - e.getPageY());
//下面if处理,也是我开始说过的,不能过于频繁执行move事件处理,例如不能拖动一个像素也出发move事件,
//所以clickPixelThresh,clickPixelThresh两个属性就是用来设置这种限制的
            if (diffX > me.clickPixelThresh || diffY > me.clickPixelThresh) {
                //详见11分析
me.startDrag(me.startX, me.startY);
            }
        }
//此时的dragThreshMet = true(看看11的最后一行代码)
        if (me.dragThreshMet) {
            current.b4Drag(e);//开始执行真正的移动**(见16)
            current.onDrag(e);//开始执行真正的移动**
            if (!current.moveOnly) {
                me.fireEvents(e, false);
            }
        }

        me.stopEvent(e);

        return true;
    }
16.Ext.dd.DD.b4Drag
     b4Drag: function(e) {
//(见17分析)
        this.setDragElPos(e.getPageX(), e.getPageY());
    }

17.Ext.dd.DD.setDragElPos
setDragElPos: function(iPageX, iPageY) {
        var el = this.getDragEl();
        this.alignElWithMouse(el, iPageX, iPageY);
    }
分享到:
评论

相关推荐

    ext.net 1.x DEMO

    以前给某物流公司做的一个demo 用到了基本的增删查改功能 以及drag功能 由于ext.net dll太大 源码中不包含 请大家自己引用1.x版本的 Ext.Net.dll和Ext.Net.xml

    Ext JS in Action, 2nd Edition

    Drag-and-drop Part 3: Building an application Chapter 13. Class system foundations Chapter 14. Building an application Book Details Title: Ext JS in Action, 2nd Edition Author: Grgur Grisogono, ...

    Ext GWT 2.0, Beginner's Guide.pdf

    Ext GWT 2.0: Beginner's Guide is a practical book that teaches you how to use the Ext GWT library to its full potential. It provides a thorough, no-nonsense explanation of the Ext GWT library, what ...

    读取EXT2分区资料的程序

     此软件支持drag and drop,但是您需要做出以下设定,在主菜单中选择“View”→“Options”→“Debug”,然后再点选“Enable write support”,确定之后在“File”下拉菜单中选择“Rescan Partition”即可。...

    Practical Ext JS 4.pdf

    非常好的一本介绍ExtJS 4的书,英文版的,不过通俗易懂,强烈推荐。...Chapter 7: Drag and Drop Chapter 8: Theming and Styling Chapter 9: MVC with Ext JS 4 Chapter 10: Extending, Unit Testing, and Packaging

    WinImage V8.10.8100 便携版 by drag0n

    2、支持 NTFS和 Linux EXT2FS/EXT3FS 映像(仅用于只读模式) 3、可连接到 Linux 分区(可查看所连接硬盘中 Linux 分区的内容) 8.10 版主要新功能: 1、兼容 VMWare Vmdk 磁盘映像。 2、修复了 Windows Vista 的兼容性...

    ExtJS界面设计工具 Ext Designer

    Designer is a graphical user interface builder for Ext JS Web applications. Its easy-to-use drag-and-drop environment enables you to quickly prototype your application's interface components, connect ...

    Ext拖动实例树和表格全

    最近项目需要,研究了一下ext 的拖动效果,现在做一些总结,c趁现在还清醒,怕以后忘记: 设置拖放的一些通用属性:enableDrag – 是否可拖动 enableDrop : 是可放置 isTarget : 是否为目标 ddGroup:“拖放组名” ...

    Ext用户扩展控件-------支持树上多个节点和叶子的拖动

    支持用shift和ctrl来选择用户要拖动的树的节点和叶子。 功能非常强大。

    ExtJS4官方指南翻译:DragandDrop拖放/Grid组件/Tree组件/容器与布局

    ExtJS4官方指南翻译:DragandDrop拖放/Grid组件/Tree组件/容器与布局

    ExtJS树形结构.docx

    enableDrag : true rootVisible : true autoScroll : true autoHeight : true width : 150 lines : true } ;"&gt;extjs实现简单的树状结构级联Ext onReady function { Ext QuickTips init ; Ext BLANK ...

    imgui-ext:用于使用派生宏构建imgui GUI的Rust库

    :warning: imgui-ext需要完全重写。 自从我第一次尝试制作程序宏以来,由于缺乏计划,它变得杂乱无章,难以维护。 在重写之前,请谨慎使用。 您还可以查看 ,它看起来很整洁! imgui-ext 派生宏。 #[derive(imgui...

    学习YUI.Ext 第六天–关于树TreePanel(Part 1)

    学习YUI.Ext 第五天–关于树TreePanel(Part 1) 效果演示:http://www.ajaxjs.com/yuicn/demos/order_tree.asp  树组件是YUI.Ext 0.40 新增的组件。虽然YUI已经自带有TREE VIEW的组件,但JACK还是决定重新开发...

    好不容易找的extjs可视化编辑器

    Full support of drag and drop for all Ext xtyped elements Eventhandler can be added containing JavaScript Advanced options to connect Json design to caller Embbeded documentation Backend ...

    extjsnaction

    1 A framework apart 2 Back to the basics 3 Events, Components, and Containers Part 2: Ext components 4 Panels, TabPanels, and Windows ...5. Organizing Components ...11 Drag and drop with Widgets

    GuiDesigner2.0.6

    Full support of drag and drop for all Ext xtyped elements Eventhandler can be added containing JavaScript Advanced options to connect Json design to caller Embbeded documentation Backend ...

    JavaScript树控件

    它结构设计分为三部分:树体,树根和树项. 实现类基于选择容器,外观与html模板参考Ext风格,可以自由定制其它html模板与外观,主要功能有: # 可方便扩展,可以与基于...# Drag & Drop,自定 #支持IE6+,Firefox,google chrome

    各种效果的jquery ui(接口)介绍

    基本的鼠标互动:拖拽(drag and dropping)、排序(sorting)、选择(selecting)、缩放(resizing) 各种互动效果:手风琴式的折叠菜单(accordions)、日历(date pickers)、对话框(dialogs)、滑动条(sliders)、表格排序...

    iquery经典教程

    http://dev.jquery.com/view/trunk/plugins/ui/tests/draggable.html 1.2 Droppables 所需要文件,drag drop ui.mouse.js ui.draggable.js ui.draggable.ext.js ui.droppable.js ui.droppable.ext.js 用法: $...

    jqert ui demo

    拖拽(drag and dropping)、排序(sorting)、选择(selecting)、缩放(resizing) 各种互动效果: 手风琴式的折叠菜单(accordions)、日历(date pickers)、对话框(dialogs)、滑动条 (sliders)、表格排序(table sorters)、...

Global site tag (gtag.js) - Google Analytics