Ленивая загрузка Angular просмотров и контроллеров на странице прокрутки

У меня есть микросайт, который использует Laravel и Angular. Это однострочный микросайт, который реагирует и разбивается на 5 разделов. Я бы хотел, чтобы они лениво загрузили их, чтобы сразу же сбросить загрузку.

<body ng-app>

 <div id="wrapper">
  <section id="intro">1</section>
  <section id="Second">2</section>
  <section id="Third">3</section>
  <section id="Fourth">4</section>
  <section id="Fifth">5</section>
 </div>

</body>

Я ищу загрузку 1 и 2 на загрузку страницы, а затем, когда вы прокручиваете страницу вниз, загрузите другое представление с хорошим угасанием, а затем загрузите его интерактивные элементы.

Ответ 1

В этом случае, вероятно, не нужно (или эффективно) лениво загружать контроллеры, но это можно сделать.

Здесь есть много вещей, поэтому я собираюсь обрабатывать его в разделах.

Ленивые загрузки просмотров на прокрутке (анимированные).

Живая демонстрация здесь (нажмите).

Разметка:

<div class="container">
  <section
    ng-repeat="section in loadedSections"
    ng-include="section+'.html'"
    scroll-load
    scroll-load-from="sections"
    scroll-load-to="loadedSections"
    ng-animate="{enter:'section-animate-enter'}"
  ></section>
</div>

Анимация CSS:

.section-animate-enter {
  -webkit-transition: 1.5s linear all;
    transition: 1.5s linear all;
    opacity: 0;
    left: 100%;
}
.section-animate-enter.section-animate-enter-active {
    opacity: 1;
    left: 0;
}

Angular логика:

app.controller('myCtrl', function($scope) {
  $scope.sections = ['top','mid','bottom']; //html files to load (top.html, etc)
  $scope.loadedSections = [$scope.sections[0]]; //loaded html files
});

app.directive('scrollLoad', function($compile) {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
      var to = scope[attrs.scrollLoadTo]; //$scope.loadedSections
      var from = scope[attrs.scrollLoadFrom]; //$scope.sections

      $window = angular.element(window);
      $window.bind('scroll', function(event) {
        var scrollTop = document.documentElement.scrollTop || document.body.scrollTop || 0;
        var scrollPos = scrollTop + document.documentElement.clientHeight;
        var elemBottom = element[0].offsetTop + element.height();
        if (scrollPos >= elemBottom) { //scrolled to bottom of scrollLoad element
          $window.unbind(event); //this listener is no longer needed.
          if (to.length < from.length) { //if there are still elements to load
            //use $apply because we're in the window event context
            scope.$apply(to.push(from[to.length])); //add next section
          }
        }
      });
    }
  };
});

КОНТРОЛЛЕРЫ с ленивой загрузкой и просмотры прокрутки (анимированные).

Живая демонстрация здесь (нажмите).

Разметка:

<div class="container">
  <!-- the "lazy" directive will get the controller first, then add ng-include -->
  <section
    ng-repeat="section in loadedSections"
    lazy="section"
    scroll-load
    scroll-load-from="sections"
    scroll-load-to="loadedSections"
    ng-animate="{enter:'section-animate-enter'}"
  ></section>
</div>

Angular Логика:

var $appControllerProvider; //see below

var app = angular.module('myApp', []);

app.config(function($controllerProvider) {
  $appControllerProvider = $controllerProvider; //cache this so that we can lazy load controllers
});

app.controller('myCtrl', function($scope) {
  $scope.sections = ['top','mid','bottom']; //html files to load (top.html, etc)
  $scope.loadedSections = [$scope.sections[0]]; //loaded html files
});

app.directive('scrollLoad', function($compile) {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
      var to = scope[attrs.scrollLoadTo]; //$scope.loadedSections
      var from = scope[attrs.scrollLoadFrom]; //$scope.sections

      $window = angular.element(window);
      $window.bind('scroll', function(event) {
        var scrollTop = document.documentElement.scrollTop || document.body.scrollTop || 0;
        var scrollPos = scrollTop + document.documentElement.clientHeight;
        var elemBottom = element[0].offsetTop + element.height();
        if (scrollPos >= elemBottom) { //scrolled to bottom of scrollLoad element
          $window.unbind(event); //this listener is no longer needed.
          if (to.length < from.length) { //if there are still elements to load
            //use $apply because we're in the window event context
            scope.$apply(to.push(from[to.length])); //add next section
          }
        }
      });
    }
  };
});

app.factory('myService', function($http, $q) {
  return {
    getController: function(fileName) {
      return $http.get(fileName+'.js').then(function(response) {
        return response.data;
      });
    }
  }
});

app.directive('lazy', function(myService, $compile, $q) {
  /* I store the directive in a variable then return it later
   * so that I can abstract directive logic into other functions below */
  var directiveReturn = {
    restrict: 'A',
    link: function(scope, element, attrs) {
      var loadName = scope.$eval(attrs.lazy);

      //this is straightforward - see the "addScript" function for explanation
      myService.getController(loadName).then(function(js) {
        return addScript(loadName, js, scope);
      }).then(function() {
        //the controller has been lazy loaded into angular
        //now use "ng-include" to lazy load the view.
        var ngInc = angular.element('<span></span>')
          .attr('ng-include', "'"+loadName+".html'")
          .attr('ng-controller', loadName+'Ctrl');
          element.append(ngInc);
          $compile(ngInc)(scope);
      });
    } //link
  }; //directive return

  /*
   * This is the magic.
   */
  var scriptPromises = {};
  function addScript(loadName, js, scope) {
    if (!scriptPromises[loadName]) { //if this controller hasn't already been loaded
      var deferred = $q.defer();
      //cache promise (which caches the controller when resolved)
      scriptPromises[loadName] = deferred.promise;

      //inject controller into a script tag
      var script = document.createElement('script');
      script.src = 'data:text/javascript,' + encodeURI(js);
      script.onload = function() {
        //this is how you lazy load a controller
        $appControllerProvider.register(loadName, window[loadName+'Ctrl']);
        //now that the controller is registered with angular, resolve the promise
        //then, it is safe to add markup that uses this controller with ng-controller
        scope.$apply(deferred.resolve());
      };
      //when this script loads, the controller will be registered and promise is resolved
      document.body.appendChild(script);
      return deferred.promise;
    }
    else { //controller already loaded
      return scriptPromises[loadName]; //use cached controller
    }
  }
  return directiveReturn;
});