`

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

    EXT.NET 1.x 提供了拖放(Drag & Drop)功能,允许用户通过鼠标操作将元素从一处拖动到另一处。这种功能常用于构建交互性更强的界面,如在日历组件中拖动事件、在列表中重新排序项目等。实现拖放功能通常涉及设置...

    ext2.0项目源代码供大家学习ext使用

    8. **Drag and Drop**:EXT支持拖放操作,允许用户通过鼠标拖动组件或数据。 9. **Ext Designer支持**:EXT 2.0可能还支持EXT Designer,一个可视化的布局编辑工具,使得非程序员也能创建EXT界面。 10. **主题和...

    EXT中文文档,EXT简明教程(Ajax框架)

    同时,它还涵盖了EXT的高级特性,如树形视图(Tree)、图表(Charts)、拖放(Drag and Drop)等。 其次,`ExtJS2.0实用简明教程.chm`可能是针对EXT JS 2.0版本的一个快速入门教程,它通常会涵盖EXT的基本概念和...

    ext-4.0.7压缩包

    8. **Drag and Drop**:EXT支持拖放功能,允许用户将组件或数据在页面上自由移动,增强交互性。 9. **Store和Model**:EXT 4.0.7 引入了更完善的Store和Model概念,增强了数据管理能力,方便与服务器端进行数据交互...

    Ext 2.3中文文档-API

    9. **拖放功能**:EXT的Drag & Drop API允许用户将元素拖放到其他位置,增强了用户体验。 10. **工具提示和提示框**:EXT提供了多种提示信息的解决方案,如Tip、Tooltip和MessageBox,文档中会详细解释它们的使用。...

    ext 3.0 中文API

    10. **Drag & Drop**:EXT支持拖放功能,可以方便地在组件之间移动元素,增强用户体验。 EXT 3.0 中文API文档包含了所有这些组件的详细说明,以及它们的配置项、方法、事件等。通过查阅CHM文件,开发者可以了解到...

    Ext.js教程和Ext.js API

    Ext.js 是一个强大的JavaScript库,专门用于构建富客户端的Web应用程序。它提供了丰富的用户界面组件和数据绑定功能,使得开发者可以构建出...因此,对于那些正在维护基于Ext.js 3.0项目的人来说,这些资源尤为宝贵。

    ext 3.2中文api目前最全

    7. **Drag & Drop**:EXT支持拖放操作,使得用户可以方便地移动和排列组件,增强了交互性。 8. **图表组件**:EXT 3.2包含一系列图表组件,如条形图、饼图、线图等,可用于数据可视化。 9. **国际化支持**:EXT ...

    EXT_JS实例,官方实例

    8. **Drag & Drop**:EXT JS支持拖放功能,允许用户在界面上自由移动组件,实现更直观的操作体验。 9. **国际化**:EXT JS内置了国际化的支持,可以轻松切换不同的语言环境。 10. **主题和皮肤**:EXT JS提供多种...

    Ext 2 中文API Documentation

    7. **拖放(Drag and Drop)**:EXT支持拖放操作,使得用户可以方便地移动和交互组件。API文档会讲解如何启用拖放功能,以及处理拖放事件。 8. **国际化(Internationalization, i18n)**:EXT 2 支持多语言应用,...

    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, ...

    Ext3.0 api帮助文档

    - **拖放(Drag and Drop)**: 支持组件间的拖放操作,实现动态布局和数据交换。 - **国际化(Internationalization)**: 提供了多语言支持,方便构建全球化应用。 以上只是Ext3.0 API的一部分关键特性,完整的...

    Ext JS in Action

    - **Drag-and-Drop Basics (拖放基础)**:介绍了Ext JS中的拖放功能,包括如何实现简单的拖放效果。 - **Drag and Drop with Widgets (带小部件的拖放)**:进一步扩展了拖放的功能,展示了如何将拖放与特定的小...

    ext教程

    ### ext教程知识点详解 #### 一、概述 **ext** 是一个非常强大的 JavaScript 类库,最初它是基于 Yahoo UI 库开发的,但现在已经完全独立。它提供了丰富的组件和功能,适用于构建复杂的 Web 应用程序。 #### 二、...

    基于ext的div拖动

    "基于EXT的div拖动"是指利用EXTJS这一强大的JavaScript框架来实现这种功能。EXTJS是一个用于构建富客户端Web应用的前端框架,它提供了丰富的组件库、数据绑定机制以及强大的布局管理,使得开发者可以方便地创建出...

    EXT 3.2.1 Demo 最全实例

    8. **拖放(Drag & Drop)**:EXT JS支持组件间的拖放操作,增强了用户体验。 9. **国际化(i18n)**:EXT JS支持多语言,方便开发面向全球用户的应用。 10. **可扩展性**:EXT JS的设计允许开发者通过插件...

    ExtDemo例子绝对能跑起来

    8. **Drag and Drop**:ExtJS支持拖放功能,允许用户通过鼠标操作移动组件或数据项。 9. **国际化和主题**:ExtJS支持多语言和自定义主题,可以轻松调整UI以适应不同文化和视觉风格。 10. **工具提示和弹出框**:...

    ext portal

    5. 拖放(Drag and Drop)事件处理 6. 位置记录和布局状态的保存与恢复 7. JavaScript编程和面向对象设计 了解并掌握这些知识点,对于开发一个动态、可定制的Web仪表板界面至关重要。在实际应用中,还需要考虑性能...

    Ext div拖动demo

    在Web开发中,动态交互是提高用户体验的重要一环,而拖放(Drag and Drop)功能正是这种交互的一种常见表现形式。在本案例中,开发者利用Ext JS库的强大力量,为元素赋予了拖动的能力,让用户可以通过鼠标操作来改变...

Global site tag (gtag.js) - Google Analytics