【前端开发】ngDraggable 实现模块拖拽的基本方法及常见问题解决

本次笔记记录使用 ngDraggable 实现模块拖拽,包含以下三点内容:
1、ng-drag,ng-drop的基本使用方法;
2、元素拖动出div区域外消失问题的解决;
3、拖动元素A进入元素B时,改变元素B的css样式;

【1】ng-drag,ng-drop的基本使用方法

1、下载ngDraggable.js文件
基本使用方法及 ngDraggable.js 文件都在这里: https://github.com/fatlinesofcode/ngDraggable

2、引入ngDraggable.js文件
(*使用框架angular,打包工具 webpack;)
在webpack.config.js文件中添加ngDraggable.js文件路径:
【前端开发】ngDraggable 实现模块拖拽的基本方法及常见问题解决_第1张图片
添加ngDraggable.js前,需要先添加angular.min.js, angular 是通过npm i angular 安装的包,这里直接添加包名,内含的angular.min.js也就可用了;

3、添加依赖项

angular.module('app', ['ngDraggable']);

4、在需要拖动的元素添加 ng-drag 相关配置项:

<div ng-drag="true" ng-drag-data="{obj}" ng-drag-start="dragStart($index)" ng-drag-stop="dragStop($index)">Draggable divdiv>

– 设置 ng-drag=“true”, 表示该div可以被拖动;
– ng-drag-data : 表示拖动元素时跟着被拖走的数据;
– ng-drag-start: 拖动行为开始发生时触发;
– ng-drag-move: 拖动元素移动时触发;
– ng-drag-stop: 拖动行为结束时触发, 可以 写 拖动元素没有进入目标元素前就停止拖动行为时 触发的事件;

5、在放置拖拽元素的 目标元素上添加 ng-drop 相关配置项:

<div ng-drop="true" ng-drop-success="onDropComplete($data,$idnex,$event)" >Drop areadiv>

– 设置 ng-drop=“true”, 表示该div 可以放置被拖拽元素;
– ng-drop-success: 当拖拽元素拖到目标区域内完成拖拽行为(鼠标松开拖拽元素算完成)时触发;
---- $data: 被拖动的数据对象
---- $index : 表示拖动数据所落的元素的下标

完成以上5个步骤就可以实现基本的拖拽功能;

【2】子元素拖动出div区域外消失问题的解决

拖动元素拖到某一个div边界块之后就消失了,但是拖出去依然有动作效果,出现这种情况,是因为要拖动的元素的某一个父元素设置了overflow属性,无论属性值设置成auto,hidden或者是scroll,都会引起这种现象的发生。解决方法有两种:

1、[overflow 属性可以去除] 去除拖动元素 父元素的 overflow属性,或改变属性值;

2、[overflow属性是必要的属性,无法去除]
在拖动动作开始的触发事件 dragStart 中, 改变拖动元素的position属性 为 绝对定位absolute。 在拖动动作停止(鼠标松开拖拽物算停止)的触发事件 dragStop 中,将position 属性恢复或设置为 unset;我以我的项目场景举例如下:

<项目场景>: 有两个table, 一个是排班列表,一个是车主列表,两个表格都设置了最大高度,超出高度显示垂直滚动条,(滚动条属性设置overflow-y:auto,这个属性无法去除),需要实现拖动车主列表中的任一车主 到 排班列表中就自动创建班次;

<实现问题>: 车主列表由于设置了 overflow属性,导致拖动table内车主模块 出 车主列表区域 就会消失;以下是车主table代码,可拖动模块是 tbody 元素内的 tr 元素;

<div class="bootstrap-table fixed-table-container">
   <table class="table table-hover table-gray">
       <thead>
           <tr style="background-color: #F5F9FB;color:#666666; font-size: 14px">
               <th class="table-driver"><div class="th-inner">车主div>th>
               <th class="table-remark" style="border-left: none;"><div class="th-inner">备注div>th>
               <th class="table-num" style="border-left: none;"><div class="th-inner">应班数div>th>
           tr>
       thead>
   table>
   <div class="dispatch-scroll-table" style="overflow-y:auto">
       <table>
           <tbody class="driver-tbody">
               
                   <td class="table-driver">
                       <div style="font-weight: bold;" ng-bind="item.id_name + '(' + item.seats + '座)'">div>
                       <div ng-bind="item.mobile">div>
                   td>
                   <td class="table-remark" style="font-weight: bold; border-left:none" ng-bind="item.remark">td>
                   <td class="table-num" style="font-weight: bold; border-left:none" ng-bind="item.schedule_num + ''">td>
               tr>
           tbody>
       table>
   div>
div>

<问题解决>:

    //拖动元素开始触发函数
    $scope.dragStart = (index, element) => {
        var e = window.event;
        var mouseX =  e.layerX || e.offsetX;
        var mouseY =  e.layerY || e.offsetY;
        if(index && element){
            var moveElement = element + ' tr:nth-child(' + index + ')'
            $(moveElement).css({position: 'absolute', left: mouseX - 40, top: mouseY, minWidth: '350'});
        }
    };

    //拖拽行为结束触发函数
    $scope.dragStop = (index, element) => {
        if(index && element){
            var moveElement = element + ' tr:nth-child(' + index + ')';
            $(moveElement).css({position: 'unset'});
        }
    };

这里需要注意:
①由于拖动开始时我们手动改变了拖动元素的position 属性为 绝对定位absolute,若列表内容过多到出现滚动条时,拖动 需要滚动条滚动才能看到的元素tr 时, 会出现拖动模块与鼠标分离的现象;所以在 dragStart函数 中还添加了鼠标跟随设置,即获取鼠标坐标,并对应设置拖动元素的left ,top 属性 以保证拖动行为发生时拖动元素实时跟随鼠标移动;
②使用了ng-repeat 插入列表项,针对拖动元素不能使用特定的class 名,需要巧妙运用css 中设置父元素的第n个子元素属性的方法,比如 以上例子中提到的 tbody 中的 第n 个tr 写为.driver-tbody tr:nth-child(n);

【3】拖动元素A进入元素B时,改变元素B的css样式;

1、项目场景:
将元素A (class=“special-block”), 拖动进入 元素B(class=“operable-block”) 时,改变元素B背景颜色 及 高度;

2、实现方法:
在 ngDraggable.js 中找到 updateDragStyles函数,根据项目场景给对应元素添加特定css 样式的类名;

#原 函数

var updateDragStyles = function(touching, dragElement) {
   if(touching){
        element.addClass('drag-enter');
        dragElement.addClass('drag-over');
    }else if(_lastDropTouch == element){
        _lastDropTouch=null;
        element.removeClass('drag-enter');
        dragElement.removeClass('drag-over');
    }
};

#根据需求更改后的函数

var updateDragStyles = function(touching, dragElement) {
   if(touching){
       var elementClassName = element[0].className.split(' ')[0];
       var dragElementClassName = dragElement[0].className.split(' ')[0];
       //结合项目指定使用位置元素class作为判断条件修改拖动元素进入目标区域时目标元素的样式,drag-enter样式添加在css文件中;
       if((elementClassName == 'operable-block') && (dragElementClassName == 'special-block')){
           element.addClass('drag-enter');
           dragElement.addClass('drag-over');
       }
   }else if(_lastDropTouch == element){
       _lastDropTouch=null;
       element.removeClass('drag-enter');
       dragElement.removeClass('drag-over');
   }
};

#在css 文件中添加类 drag-enter 的属性

/*B元素原样式*/
operable-block{
    padding: 8px; 
    margin: 10px 0; 
    background-color: #FFECB3; 
    border-radius:4px; 
    position: relative;
    cursor: pointer;
}

/* ngDraggable */
.drag-enter{
    padding: 10px !important;
    background-color:#F4A460 !important;
}

ok , 搞定!

你可能感兴趣的:(AngularJs)