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

1.相关地址:

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

2.讲解

姓名:{{item.name}},年龄:{{item.age}}

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

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

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

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

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

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

3.拖拽排序示例

页面代码

姓名:{{item.name}},年龄:{{item.age}}

js代码

/** 拖拽成功触发方法

  • index 拖拽后落下时的元素的序号(下标)
  • obj被拖动数据对象
    */
    $scope.dropComplete = function(index,obj){
    //重新排序
    var idx = $scope.content.indexOf(obj);
    $scope.content.splice(idx,1);
    $scope.content.splice(index,obj);

};

4.拖拽交换示例

页面代码

姓名:{{item.name}},年龄:{{item.age}}

JS代码

/** 拖拽成功触发方法

  • index 拖拽后落下时的元素的序号(下标)
  • obj 被拖动数据对象
    */
    $scope.dropComplete = function(index,obj){
    var idx = $scope.content.indexOf(obj);
    $scope.content[idx] = $scope.content[index];
    $scope.content[index] = obj;
    };
  1. 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,'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',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,$event: evt});
        });
      }

      _deregisterRootMoveListener();
    };

    var onDragComplete = function(evt) {


      if (!onDragSuccessCallback )return;

      scope.$apply(function () {
        onDragSuccessCallback(scope,$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,1,' + x + ',' + y + ',1)','z-index': 99999,'-webkit-transform': 'matrix3d(1,'-ms-transform': 'matrix(1,' + y + ')'
        });
      }else{
        element.css({'left':x+'px','top':y+'px','position':'fixed'});
      }
    };
    initialize();
  }
};

}])

.directive('ngDrop',['$parse','$timeout',function ($parse,$timeout,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.element);

      if (attrs.ngDragMove) {
        $timeout(function(){
          onDragMoveCallback(scope,$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.element)) {
        // call the ngDraggable ngDragSuccess element callback
        if(obj.callback){
          obj.callback(obj);
        }

        if (attrs.ngDropSuccess) {
          $timeout(function(){
            onDropCallback(scope,$event: obj,$target: scope.$eval(scope.value)});
          });
        }
      }

      if (attrs.ngDragStop) {
        $timeout(function(){
          onDragStopCallback(scope,$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',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',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,'+x+','+y+','visibility': 'visible','+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',$timeout) {
return {
restrict: 'A',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',attrs) {
element.find('*').attr('ng-cancel-drag','ng-cancel-drag');
}
};
}])
.directive('ngDragScroll',['$window','$interval','$rootScope',function($window,$interval,$rootScope) {
return {
restrict: 'A',link: function(scope,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',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',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',obj) {
      // Ignore this event if it's not for this element.
      if (obj.element[0] !== element[0]) return;

      lastMouseEvent = obj.event;
    });
  }
};

}]);

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


阅读本文之前,分享大家一张图片,看图会发现JavaScript开发需求最高,占比达到42.84%,因此掌握JavaScript语言好工作就不愁啦,工欲善其事必先利其器,那么选择IDE来开发是至关重要的,本文指出常用的几款JavaScript IDE,分析其优缺点,如有不完善的请大家补充
Promises是一种关于异步编程的规范,目的是将异步处理对象和处理规则进行规范化,为异步编程提供统一接口。本文简要的介绍了Promises的基础知识,希望我们我们能够更好的使用Promises,更轻松的编写代码。
引子 Patrick Catanzariti 是一名Web开发工程师,最近他在 sitepoint 发表了《JavaScript Beyond the Web in 2014》,介绍了JavaScript在物联网中的应用,非常有意思。做为JavaScript的爱好者和从业者,我在这里把它翻译了,以飨
小编吐血整理加上翻译,太辛苦了~求赞! 本文主要总结了JavaScript 常用功能总结,如一些常用的JS 对象,基本数据结构,功能函数等,还有一些常用的设计模式。 目录: 众所周知,JavaScript是动态的面向对象的编程语言,能够实现以下效果: 1. 丰富Web 网页功能 2. 丰富Web界面
微软于今日(2015年12月10日)宣布即将开源Chakra核心控件,并改名为“ChakraCore”,该控件包含所有Edge JavaScript 引擎的所有核心功能。ChakraCore 将于下月发布在GitHub中。 Chakra提供了顶级的JavaScript处理功能,并具有非常强大的性能优
通过统计数据库中的1000多个项目,我们发现在 JavaScript 中最常出现的错误有10个。本文会向大家介绍这些错误发生的原因以及如何防止。
TypeScript 和 JavaScript 是目前项目开发中较为流行的两种脚本语言,我们已经熟知 TypeScript 是 JavaScript 的一个超集,但是 TypeScript 与 JavaScript 之间又有什么样的区别呢?在选择开发语言时,又该如何抉择呢?
本文是2017年 JavaScript 框架回顾系列的最后的一篇文章,主要介绍 JavaScript 的后端框架情况。
本文来源于多年的 JavaScript 编码技术经验,适合所有正在使用 JavaScript 编程的开发人员阅读。本文的目的在于帮助大家更加熟练的运用 JavaScript 语言来进行开发工作。
对于前端开发人员来说,如果能够掌握交互式网页中的数据可视化技术,则是一项很棒的技能。当然,通过一些 JavaScript 的图表库也会使前端的数据可视化变得更加容易。
几乎每隔一个星期,就有一个新的 JavaScript 库席卷网络社区!Web 社区日益活跃、多样,并在多个领域快速成长。想要研究每一个重要的 JavaScript 框架和库,是个不可能完成的任务。接下来,我会分享一些前端开发的最著名和最有影响力的框架和库。下面,就让我们一起来看看,顶级的 JavaS
AngularJ.js 由google开发,2009年首次发布 很流行的前端框架 使用Angular.js创建第一个UI,成本很低 对于团队来说,AngularJ.js有许多很棒的工具可用 很适合创建一个快速、混合型复杂的解决方案 比起React,更合适于创建小型企业级应用 由Google负责维护基
Javascript框架(以下简称框架)也被称为Javascript库,是一组包含丰富功能和函数的JavaScript代码集,能够帮助开发者快速完成Web设计和开发工作。随着Web社区的越发活跃,新的框架也层出不穷,目前流行的有:Angular、React、Vue.js和Knockout等。 面对如
对于 JavaScript 社区来说,npm 的主要功能之一就是帮助开发者发掘所需的 npm Registry 中的库和框架。npm 强大的搜索功能能够帮助找到一组相关的软件包,同时其内置的的文档和使用统计信息,可以帮助开发者决定使用哪一种软件包。
前言 SpreadJS作为一款性能出众的纯前端电子表格控件,自2015年发布以来,已经被广泛应用于各领域“在线Excel”数据管理项目中。NPM,作为管理Node.js库最有力的手段,解决了很多NodeJS代码部署的问题。 如今,为让您更方便的使用产品和更好地管理项目中的SpreadJS代码,我们已
前一篇文章中,我们介绍了2017年 JavaScript 框架的整体情况。我们也了解到在众多的前端框架中,目前最为庞大又在快速增长的当属React了,本文就来重点介绍React的生态系统。
ES2017标准已经于2017年6月份正式定稿了,并广泛支持最新的特性:异步函数。如果你曾经被异步JavaScript的逻辑困扰,这么新函数正是为你设计的。
本文将会讨论10个优秀的支持JavaScript,HTML5和CSS开发,并且可以使用Markdown进行文档编写的文本编辑器。
随着现在的编程语言功能越来越成熟、复杂,内存管理也容易被大家忽略。本文将会讨论JavaScript中的内存泄漏以及如何处理,方便大家在使用JavaScript编码时,更好的应对内存泄漏带来的问题。
JavaScript 作为当前最为常见的直译式脚本语言,已经广泛应用于 Web 应用开发中。为了提高Web应用的性能,从 JavaScript 的性能优化方向入手,会是一个很好的选择。本文从加载、上下文、解析、编译、执行和捆绑等多个方面来讲解 JavaScript 的性能优化技巧,以便让更多的前端开