起因

最近在整理公司的前端库避免出现重复造轮子的情况,这里是angularjs滚动条到底部后自动加载数据的demo

infinite-scroll.directive.js

底部自动加载是根据 ngInfiniteScroll 更改的,由于Angular Style Guide提倡手动注入解耦,因此ngInfiniteScroll原来的js文件直接集成不了,这里新建directive。因为是多人开发,要考虑到代码合并后变量冲突因此每个模块应该使用闭包。更改后的ngInfiniteScroll

(function(){
   'user strict' //声明使用js严格模式
    angular
      .module('app')
      .directive('infiniteScroll', infiniteScroll)
      .value('THROTTLE_MILLISECONDS', null);
      //通过$inject来手动注入依赖从而避免重复注入和其他angular找不到变量的原因,增加了可读性。
      infiniteScroll.$inject = ['$rootScope', '$window', '$interval', 'THROTTLE_MILLISECONDS'];
    function infiniteScroll ($rootScope, $window, $interval, THROTTLE_MILLISECONDS) {
      var directive = {
          scope: {
            infiniteScroll: '&',
            infiniteScrollContainer: '=',
            infiniteScrollDistance: '=',
            infiniteScrollDisabled: '=',
            infiniteScrollUseDocumentBottom: '=',
            infiniteScrollListenForEvent: '@'
          },
          link: link,
          restrict: 'EA'
      };
      return directive;

      function link(scope, element, attrs) {
        /* */
        var changeContainer, checkInterval, checkWhenEnabled, container, handleInfiniteScrollContainer, handleInfiniteScrollDisabled, handleInfiniteScrollDistance, handleInfiniteScrollUseDocumentBottom, handler, height, immediateCheck, offsetTop, pageYOffset, scrollDistance, scrollEnabled, throttle, unregisterEventListener, useDocumentBottom, windowElement;
        windowElement = angular.element($window);
        scrollDistance = null;
        scrollEnabled = null;
        checkWhenEnabled = null;
        container = null;
        immediateCheck = true;
        useDocumentBottom = false;
        unregisterEventListener = null;
        checkInterval = false;
        height = function(element) {
          element = element[0] || element;
          if (isNaN(element.offsetHeight)) {
            return element.document.documentElement.clientHeight;
          } else {
            return element.offsetHeight;
          }
        };
        offsetTop = function(element) {
          if (!element[0].getBoundingClientRect || element.css('none')) {
            return;
          }
          return element[0].getBoundingClientRect().top + pageYOffset(element);
        };
        pageYOffset = function(element) {
          element = element[0] || element;
          if (isNaN(window.pageYOffset)) {
            return element.document.documentElement.scrollTop;
          } else {
            return element.ownerDocument.defaultView.pageYOffset;
          }
        };
        handler = function() {
          var containerBottom, containerTopOffset, elementBottom, remaining, shouldScroll;
          if (container === windowElement) {
            containerBottom = height(container) + pageYOffset(container[0].document.documentElement);
            elementBottom = offsetTop(element) + height(element);
          } else {
            containerBottom = height(container);
            containerTopOffset = 0;
            if (offsetTop(container) !== void 0) {
              containerTopOffset = offsetTop(container);
            }
            elementBottom = offsetTop(element) - containerTopOffset + height(element);
          }
          if (useDocumentBottom) {
            elementBottom = height((element[0].ownerDocument || element[0].document).documentElement);
          }
          remaining = elementBottom - containerBottom;
          shouldScroll = remaining <= height(container) * scrollDistance + 1;
          if (shouldScroll) {
            checkWhenEnabled = true;
            if (scrollEnabled) {
              if (scope.$$phase || $rootScope.$$phase) {
                return scope.infiniteScroll();
              } else {
                return scope.$apply(scope.infiniteScroll);
              }
            }
          } else {
            if (checkInterval) {
              $interval.cancel(checkInterval);
            }
            return checkWhenEnabled = false;
          }
        };
        throttle = function(func, wait) {
          var later, previous, timeout;
          timeout = null;
          previous = 0;
          later = function() {
            previous = new Date().getTime();
            $interval.cancel(timeout);
            timeout = null;
            return func.call();
          };
          return function() {
            var now, remaining;
            now = new Date().getTime();
            remaining = wait - (now - previous);
            if (remaining <= 0) {
              $interval.cancel(timeout);
              timeout = null;
              previous = now;
              return func.call();
            } else {
              if (!timeout) {
                return timeout = $interval(later, remaining, 1);
              }
            }
          };
        };
        if (THROTTLE_MILLISECONDS != null) {
          handler = throttle(handler, THROTTLE_MILLISECONDS);
        }
        scope.$on('$destroy', function() {
          container.unbind('scroll', handler);
          if (unregisterEventListener != null) {
            unregisterEventListener();
            return unregisterEventListener = null;
          }
        });
        handleInfiniteScrollDistance = function(v) {
          return scrollDistance = parseFloat(v) || 0;
        };
        scope.$watch('infiniteScrollDistance', handleInfiniteScrollDistance);
        handleInfiniteScrollDistance(scope.infiniteScrollDistance);
        handleInfiniteScrollDisabled = function(v) {
          scrollEnabled = !v;
          if (scrollEnabled && checkWhenEnabled) {
            checkWhenEnabled = false;
            return handler();
          }
        };
        scope.$watch('infiniteScrollDisabled', handleInfiniteScrollDisabled);
        handleInfiniteScrollDisabled(scope.infiniteScrollDisabled);
        handleInfiniteScrollUseDocumentBottom = function(v) {
          return useDocumentBottom = v;
        };
        scope.$watch('infiniteScrollUseDocumentBottom', handleInfiniteScrollUseDocumentBottom);
        handleInfiniteScrollUseDocumentBottom(scope.infiniteScrollUseDocumentBottom);
        changeContainer = function(newContainer) {
          if (container != null) {
            container.unbind('scroll', handler);
          }
          container = newContainer;
          if (newContainer != null) {
            return container.bind('scroll', handler);
          }
        };
        changeContainer(windowElement);
        if (scope.infiniteScrollListenForEvent) {
          unregisterEventListener = $rootScope.$on(scope.infiniteScrollListenForEvent, handler);
        }
        handleInfiniteScrollContainer = function(newContainer) {
          if ((newContainer == null) || newContainer.length === 0) {
            return;
          }
          if (newContainer.nodeType && newContainer.nodeType === 1) {
            newContainer = angular.element(newContainer);
          } else if (typeof newContainer.append === 'function') {
            newContainer = angular.element(newContainer[newContainer.length - 1]);
          } else if (typeof newContainer === 'string') {
            newContainer = angular.element(document.querySelector(newContainer));
          }
          if (newContainer != null) {
            return changeContainer(newContainer);
          } else {
            throw new Error("invalid infinite-scroll-container attribute.");
          }
        };
        scope.$watch('infiniteScrollContainer', handleInfiniteScrollContainer);
        handleInfiniteScrollContainer(scope.infiniteScrollContainer || []);
        if (attrs.infiniteScrollParent != null) {
          changeContainer(angular.element(element.parent()));
        }
        if (attrs.infiniteScrollImmediateCheck != null) {
          immediateCheck = scope.$eval(attrs.infiniteScrollImmediateCheck);
        }
        return checkInterval = $interval((function() {
          if (immediateCheck) {
            handler();
          }
          return $interval.cancel(checkInterval);
        }));
      }
  };
})()

clipboard.png
directive的引用方式还是和之前相同,这里注意给directive传值的参数名由于每个大写字母被认为是一个独立的词,而每个词之前是以一个连字符分隔的,infiniteScroll对应的是infinite-scroll。

newGoodsList.controller.js

这里是用商品列表做的例子。

(function (){
  'use strict'

  angular
      .module('app')
      .controller('newgoodsListController',newgoodsListController);

  newgoodsListController.$inject = ['$stateParams', 'goodsListService'];

  function newgoodsListController($stateParams, goodsListService){
      var vm = this;
      vm.return = true;
      vm.cateid = $stateParams.cateid;
      //定义默认参数
      var keyword = '';
      //当前页
      var pageIndex = 1;
      //每页记录数
      var pageSize = 7;
      //推荐状态 -1(全部)0(不推荐)1(推荐)
      var recommendStatus = -1;
      //自定义分类ID(热门标签)
      var custom_cateId = '';
      //品牌ID
      var brand_id = '';
      //分类ID
      var cate_id = '';
      //tag_id 标签ID
      var tag_id = '';
      //minPrice 最小价格
      var minPrice = '';
      //maxPrice 最大价格
      var maxPrice = '';
      // 排序 1:时间 2:价格 3:销量
      var order = 1;
      //true(升序)false(降序).
      var isAsc = false;
      //声明自动加载的锁,当自动加载的数据在请求的时候不会发起新请求
      var busy = false;

      getGoodsList();

      //排序选择
      vm.choose = function (num){
        if(order == num){
          isAsc = !isAsc;
          vm.isAsc = isAsc;
        }else{
          order = num;
          vm.filter_num = num;
        }
        console.log(order+':'+num+':'+isAsc);
        getGoodsList();
      }
      //商品数据请求
      function getGoodsList(){
        return goodsListService.getGoodsList(keyword, pageIndex, pageSize, recommendStatus, custom_cateId, brand_id, cate_id, tag_id, minPrice, maxPrice, order, isAsc)
          .then(function (data){
            console.log(data);
            vm.goodsList = data.data;
            load();//确保自动加载功能在第一次请求成功后再执行
          });
      }

      function load() {
        //读取总页数,并且向上取整
        var pageTotal = Math.ceil(vm.goodsList.data.rowCount/pageSize);
        //页数自加
        pageIndex ++;
        //自动加载
        vm.loadmore = function(){
          console.log('jiazai');
          //当请求进行中时不发起新请求
          if(busy) return;
          //发起请求并且阻止新请求
          busy=true;
          //当请求的页码不大于总页数时
          if(pageIndex<=pageTotal){
            return goodsListService.getGoodsList(keyword, pageIndex, pageSize, recommendStatus, custom_cateId, brand_id, cate_id, tag_id, minPrice, maxPrice, order, isAsc)
              .then(function (data){
                console.log(data.data.data.rows);
                //将新请求和数据和原来的数据合并
                Array.prototype.push.apply(vm.goodsList.data.rows,data.data.data.rows);
                busy=false;
                pageIndex++;
              });
          }
        }
      }
  }
})();

clipboard.png

clipboard.png

下拉到底部自动加载OK!


黑阔大人
278 声望33 粉丝

在这群星闪耀之年 我的征途是星辰大海


引用和评论

0 条评论