在页面滚动上延迟加载 Angular 视图和控制器 [英] Lazy loading Angular views and controllers on page scroll

查看:25
本文介绍了在页面滚动上延迟加载 Angular 视图和控制器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个使用 Laravel 和 Angular 的微型网站.这是一个响应式的一页微型网站,分为 5 个部分.我想延迟加载它们以减少一次加载.

<div id="包装器"><section id="介绍">1</section><section id="第二个">2</section><section id="第三个">3</section><section id="第四">4</section><section id="Fifth">5</section>

我想加载 1 &2 在页面加载然后当你向下滚动页面时加载另一个带有漂亮淡入的视图,然后加载它的交互式项目.

解决方案

在这种情况下,延迟加载控制器可能没有必要(或有效),但可以做到.

这里有很多事情要处理,所以我将分部分处理.

在滚动时延迟加载视图(动画).

现场演示(点击).

标记:

<节ng-repeat="加载节中的节"ng-include="section+'.html'"滚动加载滚动加载从=部分"滚动加载到 =loadedSections"ng-animate="{enter:'section-animate-enter'}"></section>

动画 CSS:

.section-animate-enter {-webkit-transition:1.5s 线性全部;过渡:1.5s线性全部;不透明度:0;左:100%;}.section-animate-enter.section-animate-enter-active {不透明度:1;左:0;}

角度逻辑:

app.controller('myCtrl', function($scope) {$scope.sections = ['top','mid','bottom'];//要加载的html文件(top.html等)$scope.loadedSections = [$scope.sections[0]];//加载的html文件});app.directive('scrollLoad', function($compile) {返回 {限制:'A',链接:函数(范围,元素,属性){var to = scope[attrs.scrollLoadTo];//$scope.loadedSectionsvar 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) {//滚动到scrollLoad元素的底部$window.unbind(事件);//不再需要这个监听器.if (to.length < from.length) {//如果还有元素要加载//使用 $apply 因为我们在窗口事件上下文中scope.$apply(to.push(from[to.length]));//添加下一节}}});}};});

延迟加载控制器和滚动视图(动画).

现场演示(点击).

标记:

<!-- "lazy" 指令将首先获取控制器,然后添加 ng-include --><节ng-repeat="加载节中的节"懒惰=部分"滚动加载滚动加载从=部分"滚动加载到 =loadedSections"ng-animate="{enter:'section-animate-enter'}"></section>

角度逻辑:

var $appControllerProvider;//见下文var app = angular.module('myApp', []);app.config(function($controllerProvider) {$appControllerProvider = $controllerProvider;//缓存它,以便我们可以延迟加载控制器});app.controller('myCtrl', function($scope) {$scope.sections = ['top','mid','bottom'];//要加载的html文件(top.html等)$scope.loadedSections = [$scope.sections[0]];//加载的html文件});app.directive('scrollLoad', function($compile) {返回 {限制:'A',链接:函数(范围,元素,属性){var to = scope[attrs.scrollLoadTo];//$scope.loadedSectionsvar 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) {//滚动到scrollLoad元素的底部$window.unbind(事件);//不再需要这个监听器.if (to.length < from.length) {//如果还有元素要加载//使用 $apply 因为我们在窗口事件上下文中scope.$apply(to.push(from[to.length]));//添加下一节}}});}};});app.factory('myService', function($http, $q) {返回 {getController:函数(文件名){返回 $http.get(fileName+'.js').then(function(response) {返回 response.data;});}}});app.directive('lazy', function(myService, $compile, $q) {/* 我将指令存储在一个变量中然后稍后返回* 这样我就可以将指令逻辑抽象到下面的其他函数中 */var 指令返回 = {限制:'A',链接:函数(范围,元素,属性){var loadName = scope.$eval(attrs.lazy);//这很简单 - 请参阅addScript"函数的说明myService.getController(loadName).then(function(js) {返回 addScript(loadName, js, scope);}).那么(函数(){//控制器已经被延迟加载到angular中//现在使用ng-include"来延迟加载视图.var ngInc = angular.element('<span></span>').attr('ng-include', "'"+loadName+".html'").attr('ng-controller', loadName+'Ctrl');element.append(ngInc);$compile(ngInc)(范围);});}//关联};//指令返回/** 这就是魔法.*/var scriptPromises = {};函数 addScript(loadName, js, scope) {if (!scriptPromises[loadName]) {//如果这个控制器还没有被加载var deferred = $q.defer();//缓存承诺(解决时缓存控制器)scriptPromises[loadName] = deferred.promise;//将控制器注入脚本标签var script = document.createElement('script');script.src = 'data:text/javascript,' + encodeURI(js);脚本.onload = 函数(){//这就是延迟加载控制器的方式$appControllerProvider.register(loadName, window[loadName+'Ctrl']);//现在控制器注册了angular,解决promise//然后,添加使用此控制器和 ng-controller 的标记是安全的scope.$apply(deferred.resolve());};//当这个脚本加载时,控制器将被注册并解决promisedocument.body.appendChild(script);返回 deferred.promise;}else {//控制器已经加载返回 scriptPromises[loadName];//使用缓存控制器}}返回指令返回;});

I have a microsite that is utilizing Laravel and Angular. It's a one page microsite that is responsive and is broken into 5 sections. I would like to lazy load them to cut down on loading all at once.

<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>

I'm looking to load 1 & 2 on page load then as you scroll down the page load the other view with a nice fade in and then load its interactive items.

解决方案

In this case it is probably not necessary (or efficient) to lazy load your controllers, but it can be done.

There are many things to tackle here, so I'm going to handle it in sections.

Lazy-loading views on scroll (animated).

Live demo here (click).

Markup:

<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>

Animation 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 logic:

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
          }
        }
      });
    }
  };
});

Lazy-loading CONTROLLERS and views on scroll (animated).

Live demo here (click).

Markup:

<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 Logic:

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;
});

这篇关于在页面滚动上延迟加载 Angular 视图和控制器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆