Sencha ExtJS 5.x的拖拽事件

对开发者来说ExtJS的一个最大的交互性设计模式就是拖拽,使用拖拽的时候,无需有太多的思考,直接做好就行了。五步可以优雅的完成一个拖拽。

拖拽的定义

拖操作的意思就是鼠标在一个UI界面上按住鼠标左键不放,并且移动。拽操作是在拖操作中鼠标释放的时候触发的操作。抽象层次上,下图就可以对拖拽进行一个总结。


为了加速开发者的开发,有一个Ext.dd类专门管理基础决策,本指导中,覆盖到的是拖拽操作的移除,非法拖拽修复和拖拽成功之后的处理。

组织拖拽类

第一眼看到Ext.dd类,你可能会被吓到。但是当我们细看的时候就会发现他们都是从FragDrop类分支来的,并且大部分都可以归为Drag和Drop组,继续深挖,在拖拽交互中可以发现有single和multi组织区分。


我们先通过插入到DOM节点的方式学习single拖拽交互,我们会利用DD和DDTarget类,它实现了拖拽操作,我们需要先明确性我们的目标。

目标

需求就是说,有家租车公司,提供cars和trucks,有三种状态,租赁,维修和正常。需要将不同状态的车放在三个不同的容器中。


我们使用DD让cars和trucks可以拖拽。我们需要创建三个容纳拖拽目标容器(DDTarget),最后,使用不同的拖拽分组确保不同的车放在不同的分组中。

第一步:开始于drag

在实例化DD的时候,获取循环div数字元素设置为可拖拽。

Ext.onReady(function() {

        // Create anobject that we'll use to implement and override drag behaviors a little later


        var overrides ={};


        // Configure thecars to be draggable

        var carElements =Ext.get('cars').select('div');

       Ext.each(carElements.elements, function(el) {

            var dd =Ext.create('Ext.dd.DD', el, 'carsDDGroup', {

               isTarget  : false

            });

            //Apply theoverrides object to the newly created instance of DD

            Ext.apply(dd,overrides);

        });


        var truckElements= Ext.get('trucks').select('div');

       Ext.each(truckElements.elements, function(el) {

            var dd = Ext.create('Ext.dd.DD', el,'trucksDDGroup', {

               isTarget  : false

            });

            Ext.apply(dd,overrides);

        });

    });

这一步,定义了一个空的overrides,存放一系列的需要的action,通过DomQuery方法获取子div元素,我们通过创建DD实例来让车可拖拽,最后通过Ext.apply将事件都放置到dd里面。

窥视拖曳节点如何受到影响

当你拖拽汽车或卡车周围的元素时,你会发现的第一件事就是它们会粘在任何被丢弃的地方。这是可以的,因为我们刚刚开始实施。重要的是要了解拖曳节点是如何受到影响的。这将有助于我们在返回到它们原来的位置时,将它们丢弃到任何不是有效的丢弃目标的对象上,这被称为“无效滴”。下面的插图使用Fixbug的HTML检查面板,并突出显示当拖动操作应用到CAMARO元素时所做的更改。


在拖动操作期间检查拖拽元素时,我们可以看到一个样式属性添加到元素中,填充了三个CSS值:位置、顶部和左侧。进一步的检查表明,当节点被拖动时,位置属性被设置为相对和左上和左属性更新。在拖动手势完成之后,样式属性与其中包含的样式保持一致。这是我们必须清理的代码,当我们修复一个无效的下降。在我们设置正确的丢弃目标之前,所有的丢弃操作都被认为是无效的。

第二步 修复无效拖拽

最不抵抗的路径是通过复位拖动操作期间应用的样式属性来修复无效的删除。这意味着拖曳元素会从鼠标下方消失,并重新出现在它起源的地方,将会非常乏味。为了使它更平滑,我们将使用Ext.FX动画这个动作。请记住,拖放类被设计为具有重写的方法。要实现修复,我们需要重写B4StastRoad、OnValueDLoad和EnDRAW方法。让我们将下面的方法添加到上面的覆盖对象中,我们将讨论它们是什么和做什么。

var overrides = {

        // Called theinstance the element is dragged.

        b4StartDrag :function() {

            // Cache thedrag element

            if (!this.el){

                this.el =Ext.get(this.getEl());

            }


            //Cache theoriginal XY Coordinates of the element, we'll use this later.

           this.originalXY = this.el.getXY();

        },

        // Called whenelement is dropped in a spot without a dropzone, or in a dropzone withoutmatching a ddgroup.

        onInvalidDrop :function() {

            // Set a flagto invoke the animated repair

           this.invalidDrop = true;

        },

        // Called whenthe drag operation completes

        endDrag :function() {

            // Invoke the animation if theinvalidDrop flag is set to true

            if(this.invalidDrop === true) {

                // Removethe drop invitation

               this.el.removeCls('dropOK');


                // Createthe animation configuration object

                varanimCfgObj = {

                   easing   : 'elasticOut',

                   duration : 1,

                   scope    : this,

                   callback : function() {

                       // Remove the position attribute

                       this.el.dom.style.position = '';

                    }

                };


                // Applythe repair animation

       this.el.setXY(this.originalXY, animCfgObj);

                delete this.invalidDrop;

            }

        },

在上面的代码中,我们首先重写B4StastRoad方法,它被称为拖拽元素在屏幕周围被拖动的瞬间,并使它成为缓存拖拽元素和原始XY坐标的理想位置,稍后我们将在这个过程中使用它。接下来,我们重写ValueDLoad,这是在拖动节点被丢弃到参与同一拖放组的丢弃目标之外的任何对象时调用的。此重写只需将本地无效DROPULL属性设置为true,将在下一个方法中使用。我们重写的最后一个方法是EntDRAW,当拖动元素不再被拖动在屏幕周围,拖拽元素不再被鼠标移动控制时被调用。此覆盖将使用动画将拖曳元素移回其原来的X和Y位置。我们在动画结束时配置动画,使用弹出式放松来提供一个凉爽有趣的弹跳效果。


第三步 配置拖拽目标

我们的要求规定,我们将允许汽车和卡车掉落在租用和修理集装箱以及他们各自的原始集装箱。要做到这一点,我们需要实例化DDATAL类的实例。这就是它的做法。

// Instantiate instances of Ext.dd.DDTarget for the cars andtrucks container

var carsDDTarget = Ext.create('Ext.dd.DDTarget','cars','carsDDGroup');

var trucksDDTarget = Ext.create('Ext.dd.DDTarget', 'trucks','trucksDDGroup');


// Instantiate instances of DDTarget for the rented and repairdrop target elements

var rentedDDTarget = Ext.create('Ext.dd.DDTarget', 'rented','carsDDGroup');

var repairDDTarget = Ext.create('Ext.dd.DDTarget', 'repair','carsDDGroup');


// Ensure that the rented and repair DDTargets will participatein the trucksDDGroup

rentedDDTarget.addToGroup('trucksDDGroup');

repairDDTarget.addToGroup('trucksDDGroup');

在上面的代码片段中,我们已经为汽车、卡车、租赁和修复元素设置了下降目标。注意,CARS容器元素只参与“CARSDDGROUP”,卡车容器元素参与“TrutksDDGROUP”。这有助于强制要求汽车和卡车只能掉落在原容器中。接下来,我们实例化租用和修复元素的实例DDATAL。最初,它们被配置为只参与“CARSDDGROUP”。为了允许他们参与“TrutksDD群”,我们必须通过AdtoToGy添加它。好,现在我们已经配置了我们的下降目标。让我们看看当我们把汽车或卡车停在一个有效的掉落元件上时会发生什么。


在执行跌落目标时,我们看到拖曳元素恰好保持其下降。也就是说,图像可以落在落下目标上的任何地方,并停留在那里。这意味着我们的辍学实现还没有完成。为了完成它,我们需要通过“另一个重写”来实现“完全删除”操作的代码,这是我们之前创建的DD实例的另一个重写。

第四步 完成拖拽

要完成该拖拽,我们需要使用DOM工具将元素从父元素实际拖动到DROP目标元素。这是通过重写DD OnDracDRAP方法实现的。将下列方法添加到重写对象中。

var overrides = {

    ...

    // Called uponsuccessful drop of an element on a DDTarget with the same

    onDragDrop :function(evtObj, targetElId) {

        // Wrap the droptarget element with Ext.Element

        var dropEl =Ext.get(targetElId);


        // Perform thenode move only if the drag element's

        // parent is notthe same as the drop target

        if(this.el.dom.parentNode.id != targetElId) {


            // Move theelement

           dropEl.appendChild(this.el);


            // Remove thedrag invitation

           this.onDragOut(evtObj, targetElId);


            // Clear thestyles

           this.el.dom.style.position ='';

           this.el.dom.style.top = '';

           this.el.dom.style.left = '';

        }

        else {

            // This wasan invalid drop, initiate a repair

           this.onInvalidDrop();

        }

    },

在上面的覆盖中,拖动元素被移动到下拉目标元素,但仅当它与拖动元素的父节点不一样时。在拖动元件移动之后,从其上清除样式。如果DROP元素与拖拽元素的父元素相同,则通过调用SIT.OnSimultDROP确保修复操作发生。

一旦成功拖拽,拖拽元素现在将从它们的父元素移动到下拉目标。用户如何知道它们是否悬停在有效的下降目标之上?我们将通过配置删除邀请来给用户一些视觉反馈。

第五步 拖放的校验增加

为了使拖放更加有用,我们需要向用户提供关于是否可以成功地进行跌落操作的反馈。这意味着我们必须重写OnDrand和OnDRAWOUT方法,将这些最后两种方法添加到重写对象中。

var overrides = {

        ...

        // Only calledwhen the drag element is dragged over the a drop target with the

same ddgroup

        onDragEnter :function(evtObj, targetElId) {

            // Colorizethe drag target if the drag node's parent is not the same as the

drop target

            if(targetElId != this.el.dom.parentNode.id) {

               this.el.addCls('dropOK');

            }

            else {

                // Removethe invitation

               this.onDragOut();

            }

        },

        // Only calledwhen element is dragged out of a dropzone with the same ddgroup

        onDragOut :function(evtObj, targetElId) {

           this.el.removeCls('dropOK');

        }

};

在上面的代码中,我们重写了OnDrand和OnDRAWOUT方法,这两种方法只在拖拽元素与参与同一拖拽组的下拉目标交互时才使用。只有当鼠标指针与拖动目标的边界相交,而拖动项处于拖动模式时,才调用OnDRAGTENT方法。同样,当拖动模式下鼠标光标首先被拖动到下拉目标的边界之外时,调用OnDRAGOUT。



通过向OnDrand和OnDRAGOUT方法添加重写,我们可以看到当鼠标光标首先相交一个有效的下拉目标时,拖动元素的背景会变绿,并且当它离开下拉目标或被丢弃时将失去其绿色背景。这就完成了DOM元素拖放的实现。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,026评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,655评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,726评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,204评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,558评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,731评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,944评论 2 314
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,698评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,438评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,633评论 2 247
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,125评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,444评论 3 255
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,137评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,103评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,888评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,772评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,669评论 2 271

推荐阅读更多精彩内容

  • 一个ExtJS应用程序的UI用户界面是由一个或者多个叫做组件的部件构成的。所有的组件都是Ext.Component...
    苏生米沿阅读 509评论 0 2
  • 第一部分 HTML&CSS整理答案 1. 什么是HTML5? 答:HTML5是最新的HTML标准。 注意:讲述HT...
    kismetajun阅读 27,111评论 1 45
  • Lua 5.1 参考手册 by Roberto Ierusalimschy, Luiz Henrique de F...
    苏黎九歌阅读 13,517评论 0 38
  • GitHub Flavored Markdown 曾经是支持 LaTeX 的,但是现在不支持了……因此若想在 RE...
    Riophae阅读 17,889评论 0 2
  • 刘慈欣著。今天刚看完。一部揭示了不以大人之心度小孩之腹。一个全新的世界。十三岁以下的世界。一个未知的世界。不同世界...
    纸墨云烟阅读 325评论 0 1