欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

深究AngularJS中ng-drag、ng-drop的用法

程序员文章站 2022-04-10 11:31:20
1.相关地址: 插件下载:https://github.com/fatlinesofcode/ngdraggable/blob/master/ngdraggable.js...

1.相关地址:

插件下载:https://github.com/fatlinesofcode/ngdraggable/blob/master/ngdraggable.js

2.讲解

<div ng-drop="true" ng-drop-success="dropcomplete($index,$data,$event)" ng-repeat="item in content">
  <li ng-drag="true" ng-drag-data="item" >
    姓名:{{item.name}},年龄:{{item.age}}
  </li>
</div>

ng-drag : 表示该元素能够被拖动

ng-drag-data : 表示拖动元素时跟着被拖走的数据

ng-drop : 表示该元素内可放置被拖动的元素

ng-drop-success : 放置在ngd-drop所在元素里后触发,一般写事件.

ng-drop-success触发的dropcomplete方法的参数说明:

  1. $index : 表示拖动的数据所落的元素的下标
  2. $data : 被拖动的数据对象

3.拖拽排序示例

页面代码

<div ng-drop="true" ng-drop-success="dropcomplete($index,$data)" ng-repeat="item in content">
  <li ng-drag="true" ng-drag-data="item" >
    姓名:{{item.name}},年龄:{{item.age}}
  </li>
</div>

js代码

//数据
$scope.content = [{'name':'张春玲','age':28},{'name':'王晰','age':26},{'name':'吴正青','age':66}];

/** 拖拽成功触发方法
*  index 拖拽后落下时的元素的序号(下标)
*  obj被拖动数据对象
*/
$scope.dropcomplete = function(index, obj){
    //重新排序
    var idx = $scope.content.indexof(obj);       
    $scope.content.splice(idx,1);
    $scope.content.splice(index,0,obj);  

};

4.拖拽交换示例

页面代码

<div ng-drop="true" ng-drop-success="dropcomplete($index,$data)" ng-repeat="item in content">
  <li ng-drag="true" ng-drag-data="item" >
    姓名:{{item.name}},年龄:{{item.age}}
  </li>
</div>

js代码

//数据
$scope.content = [{'name':'张春玲','age':28},{'name':'王晰','age':26},{'name':'吴正青','age':66}];

/** 拖拽成功触发方法
*  index 拖拽后落下时的元素的序号(下标)
*  obj 被拖动数据对象
*/
$scope.dropcomplete = function(index, obj){
    var idx = $scope.content.indexof(obj); 
    $scope.content[idx] = $scope.content[index];
    $scope.content[index] = obj;      
};

5. ngdraggable插件代码

/*
 *
 * https://github.com/fatlinesofcode/ngdraggable
 */
angular.module("ngdraggable", [])
  .service('ngdraggable', [function() {


    var scope = this;
    scope.inputevent = function(event) {
      if (angular.isdefined(event.touches)) {
        return event.touches[0];
      }
      //checking both is not redundent. if only check if touches isdefined, angularjs isdefnied will return error and stop the remaining scripty if event.originalevent is not defined.
      else if (angular.isdefined(event.originalevent) && angular.isdefined(event.originalevent.touches)) {
        return event.originalevent.touches[0];
      }
      return event;
    };

  }])
  .directive('ngdrag', ['$rootscope', '$parse', '$document', '$window', 'ngdraggable', function ($rootscope, $parse, $document, $window, ngdraggable) {
    return {
      restrict: 'a',
      link: function (scope, element, attrs) {
        scope.value = attrs.ngdrag;
        var offset,_centeranchor=false,_mx,_my,_tx,_ty,_mrx,_mry;
        var _hastouch = ('ontouchstart' in window) || window.documenttouch && document instanceof documenttouch;
        var _pressevents = 'touchstart mousedown';
        var _moveevents = 'touchmove mousemove';
        var _releaseevents = 'touchend mouseup';
        var _draghandle;

        // to identify the element in order to prevent getting superflous events when a single element has both drag and drop directives on it.
        var _myid = scope.$id;
        var _data = null;

        var _dragoffset = null;

        var _dragenabled = false;

        var _presstimer = null;

        var ondragstartcallback = $parse(attrs.ngdragstart) || null;
        var ondragstopcallback = $parse(attrs.ngdragstop) || null;
        var ondragsuccesscallback = $parse(attrs.ngdragsuccess) || null;
        var allowtransform = angular.isdefined(attrs.allowtransform) ? scope.$eval(attrs.allowtransform) : true;

        var getdragdata = $parse(attrs.ngdragdata);

        // deregistration function for mouse move events in $rootscope triggered by jqlite trigger handler
        var _deregisterrootmovelistener = angular.noop;

        var initialize = function () {
          element.attr('draggable', 'false'); // prevent native drag
          // check to see if drag handle(s) was specified
          // if queryselectorall is available, we use this instead of find
          // as jqlite find is limited to tagnames
          if (element[0].queryselectorall) {
            var draghandles = angular.element(element[0].queryselectorall('[ng-drag-handle]'));
          } else {
            var draghandles = element.find('[ng-drag-handle]');
          }
          if (draghandles.length) {
            _draghandle = draghandles;
          }
          togglelisteners(true);
        };

        var togglelisteners = function (enable) {
          if (!enable)return;
          // add listeners.

          scope.$on('$destroy', ondestroy);
          scope.$watch(attrs.ngdrag, onenablechange);
          scope.$watch(attrs.ngcenteranchor, oncenteranchor);
          // wire up touch events
          if (_draghandle) {
            // handle(s) specified, use those to initiate drag
            _draghandle.on(_pressevents, onpress);
          } else {
            // no handle(s) specified, use the element as the handle
            element.on(_pressevents, onpress);
          }
          if(! _hastouch && element[0].nodename.tolowercase() == "img"){
            element.on('mousedown', function(){ return false;}); // prevent native drag for images
          }
        };
        var ondestroy = function (enable) {
          togglelisteners(false);
        };
        var onenablechange = function (newval, oldval) {
          _dragenabled = (newval);
        };
        var oncenteranchor = function (newval, oldval) {
          if(angular.isdefined(newval))
            _centeranchor = (newval || 'true');
        };

        var isclickableelement = function (evt) {
          return (
            angular.isdefined(angular.element(evt.target).attr("ng-cancel-drag"))
          );
        };
        /*
         * when the element is clicked start the drag behaviour
         * on touch devices as a small delay so as not to prevent native window scrolling
         */
        var onpress = function(evt) {
          if(! _dragenabled)return;

          if (isclickableelement(evt)) {
            return;
          }

          if (evt.type == "mousedown" && evt.button != 0) {
            // do not start dragging on right-click
            return;
          }

          if(_hastouch){
            cancelpress();
            _presstimer = settimeout(function(){
              cancelpress();
              onlongpress(evt);
            },100);
            $document.on(_moveevents, cancelpress);
            $document.on(_releaseevents, cancelpress);
          }else{
            onlongpress(evt);
          }

        };

        var cancelpress = function() {
          cleartimeout(_presstimer);
          $document.off(_moveevents, cancelpress);
          $document.off(_releaseevents, cancelpress);
        };

        var onlongpress = function(evt) {
          if(! _dragenabled)return;
          evt.preventdefault();

          offset = element[0].getboundingclientrect();
          if(allowtransform)
            _dragoffset = offset;
          else{
            _dragoffset = {left:document.body.scrollleft, top:document.body.scrolltop};
          }


          element.centerx = element[0].offsetwidth / 2;
          element.centery = element[0].offsetheight / 2;

          _mx = ngdraggable.inputevent(evt).pagex;//ngdraggable.geteventprop(evt, 'pagex');
          _my = ngdraggable.inputevent(evt).pagey;//ngdraggable.geteventprop(evt, 'pagey');
          _mrx = _mx - offset.left;
          _mry = _my - offset.top;
          if (_centeranchor) {
            _tx = _mx - element.centerx - $window.pagexoffset;
            _ty = _my - element.centery - $window.pageyoffset;
          } else {
            _tx = _mx - _mrx - $window.pagexoffset;
            _ty = _my - _mry - $window.pageyoffset;
          }

          $document.on(_moveevents, onmove);
          $document.on(_releaseevents, onrelease);
          // this event is used to receive manually triggered mouse move events
          // jqlite unfortunately only supports triggerhandler(...)
          // see http://api.jquery.com/triggerhandler/
          // _deregisterrootmovelistener = $rootscope.$on('draggable:_triggerhandlermove', onmove);
          _deregisterrootmovelistener = $rootscope.$on('draggable:_triggerhandlermove', function(event, origevent) {
            onmove(origevent);
          });
        };

        var onmove = function (evt) {
          if (!_dragenabled)return;
          evt.preventdefault();

          if (!element.hasclass('dragging')) {
            _data = getdragdata(scope);
            element.addclass('dragging');
            $rootscope.$broadcast('draggable:start', {x:_mx, y:_my, tx:_tx, ty:_ty, event:evt, element:element, data:_data});

            if (ondragstartcallback ){
              scope.$apply(function () {
                ondragstartcallback(scope, {$data: _data, $event: evt});
              });
            }
          }

          _mx = ngdraggable.inputevent(evt).pagex;//ngdraggable.geteventprop(evt, 'pagex');
          _my = ngdraggable.inputevent(evt).pagey;//ngdraggable.geteventprop(evt, 'pagey');

          if (_centeranchor) {
            _tx = _mx - element.centerx - _dragoffset.left;
            _ty = _my - element.centery - _dragoffset.top;
          } else {
            _tx = _mx - _mrx - _dragoffset.left;
            _ty = _my - _mry - _dragoffset.top;
          }

          moveelement(_tx, _ty);

          $rootscope.$broadcast('draggable:move', { x: _mx, y: _my, tx: _tx, ty: _ty, event: evt, element: element, data: _data, uid: _myid, dragoffset: _dragoffset });
        };

        var onrelease = function(evt) {
          if (!_dragenabled)
            return;
          evt.preventdefault();
          $rootscope.$broadcast('draggable:end', {x:_mx, y:_my, tx:_tx, ty:_ty, event:evt, element:element, data:_data, callback:ondragcomplete, uid: _myid});
          element.removeclass('dragging');
          element.parent().find('.drag-enter').removeclass('drag-enter');
          reset();
          $document.off(_moveevents, onmove);
          $document.off(_releaseevents, onrelease);

          if (ondragstopcallback ){
            scope.$apply(function () {
              ondragstopcallback(scope, {$data: _data, $event: evt});
            });
          }

          _deregisterrootmovelistener();
        };

        var ondragcomplete = function(evt) {


          if (!ondragsuccesscallback )return;

          scope.$apply(function () {
            ondragsuccesscallback(scope, {$data: _data, $event: evt});
          });
        };

        var reset = function() {
          if(allowtransform)
            element.css({transform:'', 'z-index':'', '-webkit-transform':'', '-ms-transform':''});
          else
            element.css({'position':'',top:'',left:''});
        };

        var moveelement = function (x, y) {
          if(allowtransform) {
            element.css({
              transform: 'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, ' + x + ', ' + y + ', 0, 1)',
              'z-index': 99999,
              '-webkit-transform': 'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, ' + x + ', ' + y + ', 0, 1)',
              '-ms-transform': 'matrix(1, 0, 0, 1, ' + x + ', ' + y + ')'
            });
          }else{
            element.css({'left':x+'px','top':y+'px', 'position':'fixed'});
          }
        };
        initialize();
      }
    };
  }])

  .directive('ngdrop', ['$parse', '$timeout', '$window', '$document', 'ngdraggable', function ($parse, $timeout, $window, $document, ngdraggable) {
    return {
      restrict: 'a',
      link: function (scope, element, attrs) {
        scope.value = attrs.ngdrop;
        scope.istouching = false;

        var _lastdroptouch=null;

        var _myid = scope.$id;

        var _dropenabled=false;

        var ondropcallback = $parse(attrs.ngdropsuccess);// || function(){};

        var ondragstartcallback = $parse(attrs.ngdragstart);
        var ondragstopcallback = $parse(attrs.ngdragstop);
        var ondragmovecallback = $parse(attrs.ngdragmove);

        var initialize = function () {
          togglelisteners(true);
        };

        var togglelisteners = function (enable) {
          // remove listeners

          if (!enable)return;
          // add listeners.
          scope.$watch(attrs.ngdrop, onenablechange);
          scope.$on('$destroy', ondestroy);
          scope.$on('draggable:start', ondragstart);
          scope.$on('draggable:move', ondragmove);
          scope.$on('draggable:end', ondragend);
        };

        var ondestroy = function (enable) {
          togglelisteners(false);
        };
        var onenablechange = function (newval, oldval) {
          _dropenabled=newval;
        };
        var ondragstart = function(evt, obj) {
          if(! _dropenabled)return;
          istouching(obj.x,obj.y,obj.element);

          if (attrs.ngdragstart) {
            $timeout(function(){
              ondragstartcallback(scope, {$data: obj.data, $event: obj});
            });
          }
        };
        var ondragmove = function(evt, obj) {
          if(! _dropenabled)return;
          istouching(obj.x,obj.y,obj.element);

          if (attrs.ngdragmove) {
            $timeout(function(){
              ondragmovecallback(scope, {$data: obj.data, $event: obj});
            });
          }
        };

        var ondragend = function (evt, obj) {

          // don't listen to drop events if this is the element being dragged
          // only update the styles and return
          if (!_dropenabled || _myid === obj.uid) {
            updatedragstyles(false, obj.element);
            return;
          }
          if (istouching(obj.x, obj.y, obj.element)) {
            // call the ngdraggable ngdragsuccess element callback
            if(obj.callback){
              obj.callback(obj);
            }

            if (attrs.ngdropsuccess) {
              $timeout(function(){
                ondropcallback(scope, {$data: obj.data, $event: obj, $target: scope.$eval(scope.value)});
              });
            }
          }

          if (attrs.ngdragstop) {
            $timeout(function(){
              ondragstopcallback(scope, {$data: obj.data, $event: obj});
            });
          }

          updatedragstyles(false, obj.element);
        };

        var istouching = function(mousex, mousey, dragelement) {
          var touching= hittest(mousex, mousey);
          scope.istouching = touching;
          if(touching){
            _lastdroptouch = element;
          }
          updatedragstyles(touching, dragelement);
          return touching;
        };

        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 hittest = function(x, y) {
          var bounds = element[0].getboundingclientrect();// ngdraggable.getprivoffset(element);
          x -= $document[0].body.scrollleft + $document[0].documentelement.scrollleft;
          y -= $document[0].body.scrolltop + $document[0].documentelement.scrolltop;
          return x >= bounds.left
            && x <= bounds.right
            && y <= bounds.bottom
            && y >= bounds.top;
        };

        initialize();
      }
    };
  }])
  .directive('ngdragclone', ['$parse', '$timeout', 'ngdraggable', function ($parse, $timeout, ngdraggable) {
    return {
      restrict: 'a',
      link: function (scope, element, attrs) {
        var img, _allowclone=true;
        var _dragoffset = null;
        scope.cloneddata = {};
        var initialize = function () {

          img = element.find('img');
          element.attr('draggable', 'false');
          img.attr('draggable', 'false');
          reset();
          togglelisteners(true);
        };


        var togglelisteners = function (enable) {
          // remove listeners

          if (!enable)return;
          // add listeners.
          scope.$on('draggable:start', ondragstart);
          scope.$on('draggable:move', ondragmove);
          scope.$on('draggable:end', ondragend);
          preventcontextmenu();

        };
        var preventcontextmenu = function() {
          // element.off('mousedown touchstart touchmove touchend touchcancel', absorbevent_);
          img.off('mousedown touchstart touchmove touchend touchcancel', absorbevent_);
          // element.on('mousedown touchstart touchmove touchend touchcancel', absorbevent_);
          img.on('mousedown touchstart touchmove touchend touchcancel', absorbevent_);
        };
        var ondragstart = function(evt, obj, elm) {
          _allowclone=true;
          if(angular.isdefined(obj.data.allowclone)){
            _allowclone=obj.data.allowclone;
          }
          if(_allowclone) {
            scope.$apply(function () {
              scope.cloneddata = obj.data;
            });
            element.css('width', obj.element[0].offsetwidth);
            element.css('height', obj.element[0].offsetheight);

            moveelement(obj.tx, obj.ty);
          }

        };
        var ondragmove = function(evt, obj) {
          if(_allowclone) {

            _tx = obj.tx + obj.dragoffset.left;
            _ty = obj.ty + obj.dragoffset.top;

            moveelement(_tx, _ty);
          }
        };
        var ondragend = function(evt, obj) {
          //moveelement(obj.tx,obj.ty);
          if(_allowclone) {
            reset();
          }
        };

        var reset = function() {
          element.css({left:0,top:0, position:'fixed', 'z-index':-1, visibility:'hidden'});
        };
        var moveelement = function(x,y) {
          element.css({
            transform: 'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, '+x+', '+y+', 0, 1)', 'z-index': 99999, 'visibility': 'visible',
            '-webkit-transform': 'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, '+x+', '+y+', 0, 1)',
            '-ms-transform': 'matrix(1, 0, 0, 1, '+x+', '+y+')'
            //,margin: '0' don't monkey with the margin,
          });
        };

        var absorbevent_ = function (event) {
          var e = event;//.originalevent;
          e.preventdefault && e.preventdefault();
          e.stoppropagation && e.stoppropagation();
          e.cancelbubble = true;
          e.returnvalue = false;
          return false;
        };

        initialize();
      }
    };
  }])
  .directive('ngpreventdrag', ['$parse', '$timeout', function ($parse, $timeout) {
    return {
      restrict: 'a',
      link: function (scope, element, attrs) {
        var initialize = function () {

          element.attr('draggable', 'false');
          togglelisteners(true);
        };


        var togglelisteners = function (enable) {
          // remove listeners

          if (!enable)return;
          // add listeners.
          element.on('mousedown touchstart touchmove touchend touchcancel', absorbevent_);
        };


        var absorbevent_ = function (event) {
          var e = event.originalevent;
          e.preventdefault && e.preventdefault();
          e.stoppropagation && e.stoppropagation();
          e.cancelbubble = true;
          e.returnvalue = false;
          return false;
        };

        initialize();
      }
    };
  }])
  .directive('ngcanceldrag', [function () {
    return {
      restrict: 'a',
      link: function (scope, element, attrs) {
        element.find('*').attr('ng-cancel-drag', 'ng-cancel-drag');
      }
    };
  }])
  .directive('ngdragscroll', ['$window', '$interval', '$timeout', '$document', '$rootscope', function($window, $interval, $timeout, $document, $rootscope) {
    return {
      restrict: 'a',
      link: function(scope, element, attrs) {
        var intervalpromise = null;
        var lastmouseevent = null;

        var config = {
          verticalscroll: attrs.verticalscroll || true,
          horizontalscroll: attrs.horizontalscroll || true,
          activationdistance: attrs.activationdistance || 75,
          scrolldistance: attrs.scrolldistance || 15
        };


        var reqanimframe = (function() {
          return window.requestanimationframe ||
            window.webkitrequestanimationframe ||
            window.mozrequestanimationframe ||
            window.orequestanimationframe ||
            window.msrequestanimationframe ||
            function( /* function framerequestcallback */ callback, /* domelement element */ element ) {
              window.settimeout(callback, 1000 / 60);
            };
        })();

        var animationison = false;
        var createinterval = function() {
          animationison = true;

          function nextframe(callback) {
            var args = array.prototype.slice.call(arguments);
            if(animationison) {
              reqanimframe(function () {
                $rootscope.$apply(function () {
                  callback.apply(null, args);
                  nextframe(callback);
                });
              })
            }
          }

          nextframe(function() {
            if (!lastmouseevent) return;

            var viewportwidth = math.max(document.documentelement.clientwidth, window.innerwidth || 0);
            var viewportheight = math.max(document.documentelement.clientheight, window.innerheight || 0);

            var scrollx = 0;
            var scrolly = 0;

            if (config.horizontalscroll) {
              // if horizontal scrolling is active.
              if (lastmouseevent.clientx < config.activationdistance) {
                // if the mouse is on the left of the viewport within the activation distance.
                scrollx = -config.scrolldistance;
              }
              else if (lastmouseevent.clientx > viewportwidth - config.activationdistance) {
                // if the mouse is on the right of the viewport within the activation distance.
                scrollx = config.scrolldistance;
              }
            }

            if (config.verticalscroll) {
              // if vertical scrolling is active.
              if (lastmouseevent.clienty < config.activationdistance) {
                // if the mouse is on the top of the viewport within the activation distance.
                scrolly = -config.scrolldistance;
              }
              else if (lastmouseevent.clienty > viewportheight - config.activationdistance) {
                // if the mouse is on the bottom of the viewport within the activation distance.
                scrolly = config.scrolldistance;
              }
            }



            if (scrollx !== 0 || scrolly !== 0) {
              // record the current scroll position.
              var currentscrollleft = ($window.pagexoffset || $document[0].documentelement.scrollleft);
              var currentscrolltop = ($window.pageyoffset || $document[0].documentelement.scrolltop);

              // remove the transformation from the element, scroll the window by the scroll distance
              // record how far we scrolled, then reapply the element transformation.
              var elementtransform = element.css('transform');
              element.css('transform', 'initial');

              $window.scrollby(scrollx, scrolly);

              var horizontalscrollamount = ($window.pagexoffset || $document[0].documentelement.scrollleft) - currentscrollleft;
              var verticalscrollamount = ($window.pageyoffset || $document[0].documentelement.scrolltop) - currentscrolltop;

              element.css('transform', elementtransform);

              lastmouseevent.pagex += horizontalscrollamount;
              lastmouseevent.pagey += verticalscrollamount;

              $rootscope.$emit('draggable:_triggerhandlermove', lastmouseevent);
            }

          });
        };

        var clearinterval = function() {
          animationison = false;
        };

        scope.$on('draggable:start', function(event, obj) {
          // ignore this event if it's not for this element.
          if (obj.element[0] !== element[0]) return;

          if (!animationison) createinterval();
        });

        scope.$on('draggable:end', function(event, obj) {
          // ignore this event if it's not for this element.
          if (obj.element[0] !== element[0]) return;

          if (animationison) clearinterval();
        });

        scope.$on('draggable:move', function(event, obj) {
          // ignore this event if it's not for this element.
          if (obj.element[0] !== element[0]) return;

          lastmouseevent = obj.event;
        });
      }
    };
  }]);

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。