angular-loading用法以及注意事项

css
.dw-loading {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    text-align: center;
    display: none;
}

.dw-loading:before {
    content: '';
    display: inline-block;
    height: 100%;
    vertical-align: middle;
}

.dw-loading.dw-loading-active {
    display: block;
}

.dw-loading.dw-loading-overlay {
    background-color: rgba(255, 255, 255, .7);
    z-index: 9999;
}

.dw-loading > .dw-loading-body {
    display: inline-block;
    vertical-align: middle;
    position: relative;
}

.dw-loading > .dw-loading-body > .dw-loading-spinner {
    position: relative;
}

.dw-loading > .dw-loading-body > .dw-loading-text {
    position: relative;
    top: 25px;
    font-weight: bold;
    font-size: 11px;
    text-shadow: 0 0 2px rgb(255, 255, 255);
}
--js--
(function (window, angular, undefined) {
  'use strict';

  angular.module('darthwade.dwLoading', [])

    .value('dwLoadingOptions', {
      active: false,
      text: 'Loading...',
      className: '',
      overlay: true,
      spinner: true,
      spinnerOptions: {
        lines: 12,            // The number of lines to draw
        length: 7,            // The length of each line
        width: 4,             // The line thickness
        radius: 10,           // The radius of the inner circle
        rotate: 0,            // Rotation offset
        corners: 1,           // Roundness (0..1)
        color: '#000',        // #rgb or #rrggbb
        direction: 1,         // 1: clockwise, -1: counterclockwise
        speed: 2,             // Rounds per second
        trail: 100,           // Afterglow percentage
        opacity: 1/4,         // Opacity of the lines
        fps: 20,              // Frames per second when using setTimeout()
        zIndex: 2e9,          // Use a high z-index by default
        className: 'dw-spinner', // CSS class to assign to the element
        top: 'auto',          // center vertically
        left: 'auto',         // center horizontally
        position: 'relative'  // element position
      }
    })

    .service('dwLoading', ['$rootScope', 'dwLoadingOptions', function ($rootScope, dwLoadingOptions) {
      var self = this;

      /**
       * Sets default options (@see `dwLoadingOptions`)
       * @param {object} options
       */
      self.setDefaultOptions = function (options) {
        extend(true, dwLoadingOptions, options);
      };

      /**
       * Activates spinner by key
       * @param {string} key
       */
      self.start = function (key) {
        $rootScope.$broadcast('$dwLoadingStart', key);
      };

      /**
       * Deactivates spinner by key
       * @param {string} key
       */
      self.finish = function (key) {
        $rootScope.$broadcast('$dwLoadingFinish', key);
      };
    }])

    // Shortcut
    .factory('$loading', ['dwLoading', function(dwLoading) {
      return dwLoading;
    }])

    .directive('dwLoading', ['$window', '$compile', 'dwLoadingOptions', function ($window, $compile, dwLoadingOptions) {
      return {
        scope: true,
        link: function (scope, element, attrs) {
          scope.spinner = null;
          scope.key = attrs.dwLoading || false;

          /**
           * Starts spinner
           */
          scope.start = function () {
            if (scope.container) {
              scope.container.addClass('dw-loading-active');
            }
            if (scope.spinner) {
              scope.spinner.spin(scope.spinnerContainer[0]);
            }
          };

          /**
           * Stops spinner
           */
          scope.finish = function () {
            if (scope.container) {
              scope.container.removeClass('dw-loading-active');
            }
            if (scope.spinner) {
              scope.spinner.stop();
            }
          };
          
          scope.$watch(attrs.dwLoadingOptions, function (options) {
            scope.finish();

            scope.options = extend(true, {}, dwLoadingOptions, options);

            // Build template
            var body = angular.element('<div></div>')
              .addClass('dw-loading-body');
            scope.container = angular.element('<div></div>')
              .addClass('dw-loading')
              .append(body);

            if (scope.options.overlay) {
              scope.container.addClass('dw-loading-overlay');
            }
            if (scope.options.className) {
              scope.container.addClass(scope.options.className);
            }
            if (scope.options.spinner) {
              scope.spinnerContainer = angular.element('<div></div>')
                .addClass('dw-loading-spinner');
              body.append(scope.spinnerContainer);
              scope.spinner = new $window.Spinner(scope.options.spinnerOptions);
            }
            if (scope.options.text) {
              var text = angular.element('<div></div>')
                .addClass('dw-loading-text')
                .text(scope.options.text);
              body.append(text);
            }

            element.append(scope.container);
//            $compile(container)(scope);

            if (scope.options.active || !scope.key) {
              scope.start();
            }
          }, true);

          scope.$on('$dwLoadingStart', function (event, key) {
            if (key === scope.key) {
              scope.start();
            }
          });

          scope.$on('$dwLoadingFinish', function (event, key) {
            if (key === scope.key) {
              scope.finish();
            }
          });

          scope.$on('$destroy', function () {
            scope.finish();
            scope.spinner = null;
          });
        }
      };
    }]);

  /**
   * Extends the destination object `dst` by copying all of the properties from the `src` object(s)
   * to `dst`. You can specify multiple `src` objects.
   *
   * @param   {Boolean} deep If true, the merge becomes recursive (optional)
   * @param   {Object}  dst  Destination object.
   * @param   {Object}  src  Source object(s).
   * @returns {Object}       Reference to `dst`.
   */
  function extend(dst) {
    var deep = false,
      i = 1;

    if (typeof dst === 'boolean') {
      deep = dst;
      dst = arguments[1] || {};
      i++;
    }

    angular.forEach([].slice.call(arguments, i), function (obj) {
      var array, clone, copy, key, src;

      for (key in obj) {
        src = dst[key];
        copy = obj[key];

        if (dst === copy) {
          continue;
        }

        if (deep && copy && (angular.isObject(copy) ||
          (array = angular.isArray(copy)))) {

          if (array) {
            clone = (src && angular.isArray(src)) ? src : [];
          } else {
            clone = (src && angular.isObject(src)) ? src : {};
          }

          dst[key] = extend(deep, clone, copy);
        }
        else if (copy !== undefined) {
          dst[key] = copy;
        }
      }
    });

    return dst;
  }

})(window, window.angular);

--html--
<!DOCTYPE html> <html> <head> <title>Angular Block Spinner</title> <link rel="stylesheet" type="text/css" href="angular-loading.css" /> <script data-require="angular.js@1.2.13" data-semver="1.2.13" src="http://code.angularjs.org/1.2.13/angular.js"></script> <script data-require="spin.js@1.2.7" data-semver="1.2.7" src="//cdnjs.cloudflare.com/ajax/libs/spin.js/1.2.7/spin.min.js"></script> <script type="text/javascript" src="angular-loading.js"></script>
--js-- <script> angular.module('demoApp', [ 'darthwade.dwLoading' ]) .controller('MainCtrl', function ($scope, $loading) { $scope.startLoading = function (name) { $loading.start(name); }; $scope.finishLoading = function (name) { $loading.finish(name); }; }) </script> </head> <body ng-app="demoApp"> <div ng-controller="MainCtrl"> <div class="sample sample-1"> <h2>Basic</h2> <input type="button" value="Start Loading" ng-click="startLoading('sample-1')" /> <input type="button" value="Finish Loading" ng-click="finishLoading('sample-1')" /> <div class="box small" dw-loading="sample-1"> <p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.</p> <p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.</p> </div> </div> <div class="sample sample-2"> <h2>Autoload</h2> <input type="button" value="Start Loading" ng-click="startLoading('sample-2')" /> <input type="button" value="Finish Loading" ng-click="finishLoading('sample-2')" /> <div class="box small" dw-loading="sample-2" dw-loading-options="{active: true}"> <p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.</p> <p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.</p> </div> </div> <div class="sample sample-3"> <h2>No text, no overlay</h2> <input type="button" value="Start Loading" ng-click="startLoading('sample-3')" /> <input type="button" value="Finish Loading" ng-click="finishLoading('sample-3')" /> <div class="box small" dw-loading="sample-3" dw-loading-options="{active: true, text: false, overlay: false}"> <p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.</p> <p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.</p> </div> </div> <div class="sample sample-4"> <h2>Custom styling, custom spinner, custom text</h2> <input type="button" value="Start Loading" ng-click="startLoading('sample-4')" /> <input type="button" value="Finish Loading" ng-click="finishLoading('sample-4')" /> <div class="box small" dw-loading="sample-4" dw-loading-options="{active: true, text: 'Custom text', className: 'custom-loading', spinnerOptions: {lines: 12, length: 20, width: 6, radius: 20, color: '#f0f', direction: -1, speed: 3}}"> <p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.</p> <p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.</p> </div> </div> </div> </body> </html>
如果 dw-loading="" 写在form上或者form的父级会导致 angularjs form表单验证失败
--参数--
dw-loading-options="";
{
  active: false, // Defines current loading state
  text: 'Loading...', // Display text
  className: '', // Custom class, added to directive
  overlay: true, // Display overlay
  spinner: true, // Display spinner
  spinnerOptions: {
    lines: 12, // The number of lines to draw
    length: 7, // The length of each line
    width: 4, // The line thickness
    radius: 10, // The radius of the inner circle
    rotate: 0, // Rotation offset
    corners: 1, // Roundness (0..1)
    color: '#000', // #rgb or #rrggbb
    direction: 1, // 1: clockwise, -1: counterclockwise
    speed: 2, // Rounds per second
    trail: 100, // Afterglow percentage
    opacity: 1 / 4, // Opacity of the lines
    fps: 20, // Frames per second when using setTimeout()
    zIndex: 2e9, // Use a high z-index by default
    className: 'dw-spinner', // CSS class to assign to the element
    top: 'auto', // Center vertically
    left: 'auto', // Center horizontally
    position: 'relative' // Element position
  }
}
<div dw-loading="key" dw-loading-options="{className: 'custom-loading', spinnerOptions: {className: 'custom-spinner'}}" class="my-block">
  <p>Content</p>
</div>