Angularjs选项卡在渲染时加载微调器

我有一个带有一些标签的页面,每个标签都有大量的angularjs绑定。 这是我面临问题的示例页面。每个标签大约需要10秒才能呈现。

因此我计划在制表符渲染时给出一个加载微调器。 因此,我计划在单击选项卡时显示加载微调器,并在ng-repeat的末尾( $last )移除微调器。

在ng-click on选项卡中,我激活了旋转装载机

 
  • {{tab.title}}

在控制器中

 $scope.onClickTab = function (tab) { showLoader(); $scope.currentTab = tab.url; } 

要检查ng-repeat是否已完成,我使用了以下指令

 .directive('onFinishRender', function ($timeout) { return { restrict: 'A', link: function (scope, element, attr) { if (scope.$last === true) { $timeout(function () { scope.$emit('ngRepeatFinished'); }); } } } }); $scope.$on('ngRepeatFinished', function (ngRepeatFinishedEvent) { removeLoader(); }); 

showLoader和removeLoader是简单的函数,它附加和删除具有简单加载微调器的div。

 function showLoader() { $('body').append('
'); } function removeLoader() { $('.loader').fadeOut(function () { $(this).remove(); }); }

预期结果:单击选项卡时显示旋转加载程序并显示直到ng-repeat完成。(即单击的选项卡完全呈现)

实际结果:单击选项卡时未显示加载程序,它几乎出现在ng-repaet的末尾,并显示几分钟。 在这里你可以观察到上述行为。 我认为由于角度绑定过程导致页面冻结,页面无法显示微调器。

任何人都可以帮我解决这个问题吗?

您可以像这样更改代码:

 $timeout(function() { $scope.currentTab = tab.url }, 100); 

演示: http : //jsfiddle.net/eRGT8/1053/

我所做的是,我将currentTab更改为下一个摘要周期。 (这是一种黑客,而不是我引以为豪的解决方案。)因此,在第一个摘要周期(在调用$timeout之前),只显示加载。 在下一个摘要周期中,阻塞ng-repeat内容开始工作,但由于我们之前显示加载,因此显示。

🙂

这解决了您的问题,但运行长时间运行并阻止完全挂起浏览器的javascript并不是一个好的用户体验。 此外,由于浏览器完全挂起,加载gif不会动画,只会显示。

我强烈建议首先阅读这个SO线程,由AngularJS本人的作者自己编写,解决根本问题。

延迟AngularJS路由更改,直到加载模型以防止闪烁

然后,Misko通过建议使用$ routeProvider来回答他自己关于这个主题的问题,如下所示:

  $routeProvider. when('/phones', { templateUrl: 'partials/phone-list.html', controller: PhoneListCtrl, resolve: PhoneListCtrl.resolve}). // <-- this is the connection when resolved when('/phones/:phoneId', { templateUrl: 'partials/phone-detail.html', controller: PhoneDetailCtrl, resolve: PhoneDetailCtrl.resolve}). otherwise({redirectTo: '/phones'}); 

以下是您正在寻找的成品/解决方案,这是AngularJS手机演示的增强版:

http://mhevery.github.io/angular-phonecat/app/#/phones

这需要NgRoute(),但这是正确的方法。 在这里使用$ timeout似乎对我很苛刻 - 我不是说你需要ngRoute然而我不知道如何在没有它的情况下将它拉下来(我知道你的标签目前可能没有路由,但我希望它有所帮助) 。

此外,也可以使用angular.element(document).ready(function(){})找到; 对于你的初始有效载荷也将解决你的哇哇。

 angular.element(document).ready(function(){ $('.loading').remove(); // Just an example dont modify the dom outside of a directive! alert('Loaded!'); }); 

你可以看到没有$ timeout(function(){}); 使用任何一种方法,这里是angular.element.ready()的certificate工作 - 没有路由器:

工作演示 http://codepen.io/nicholasabrams/pen/MwOMNR

*如果你真的需要我,我可以制作一些标签,但你没有在你的post中提供一个有效的代码示例,所以我使用另一个我为另一个线程制作的演示来展示解决方案。

这里是另一个解决方案,这次我用你的例子!

http://jsfiddle.net/eRGT8/1069/

这次我在$ index === $ last(ngRepeat()中的最后一个元素)时触发一个函数,这样装载器从dom中移除或者当重复完成其业务时隐藏起来)

我通常使用ng-if在我的HTML中解决这个问题。

在你的情况下,这将变成如下:

 
    Content loading... No tabs available
  • {{tab.title}}

我认为在重新呈现页面时显示加载微调器并不是可能的。 渲染引擎是单线程的。 除网络操作外,几乎所有事情都发生在一个线程中。 在Firefox和Safari中,这是浏览器的主线程。 在chrome中,它是制表符进程的主线程。 网络操作可以由几个并行线程执行。

你可以在这里阅读

只有一种方法可以解决这个问题 – 重新设计页面:仅显示部分数据,延迟加载等。

您可以为每个li示例加载计数器创建自定义指令,然后添加将保存计数器的依赖服务,并在链接函数内的每个指令中调用

 var app = angular.module('app', []); app.controller('List', function(LoadingCounter) { this.tabs = [{ title: "Test tab", url: "http://google.sk" }, { title: "Test tab", url: "http://google.sk" }, { title: "Test tab", url: "http://google.sk" }] this.LoadingCounter = LoadingCounter; }); app.directive('spinningLoader', function(LoadingCounter) { return { restrict: 'A', scope: { max: "=" }, link: function(scope) { LoadingCounter.updateCounter(scope.max); } } }); app.factory('LoadingCounter', function($timeout) { var service = {}; service.currentCounter = 0; service.finished = false; service.updateCounter = function(max) { service.currentCounter++; if (service.currentCounter == max) { //example timeout $timeout(function() { service.finished = true; }, 2000); } } service.isFinished = function() { return service.finished; } return service; }); 
 .hidden { display: none; } 
   
Loading
  • {{tab.title}}