在ui-routerparsing过程中应用加载微调器

resolve $routeProvider属性允许在相应的视图被呈现之前执行一些工作。

如果我想在执行这些作业时显示一个微调框以增加用户体验,该怎么办?
事实上,否则用户会感觉到应用程序被阻塞,因为例如几毫秒没有显示视图元素。

当然,还有一种方法可以从当前视图中定义一个全局的div元素来显示,以显示微调,这要感谢$scope.$rootChangeStart函数。
但是我不想用一个可怜的微调来隐藏整个页面。
我想我的web应用程序的一些页面加载显示的方式不同。

我遇到了这个有趣的post,其中包含我上面描述的确切问题:

这种方法导致了糟糕的UI体验。 用户点击一个button来刷新列表或其他东西,整个屏幕被覆盖在一个通用的微调,因为库无法显示一个微调只是实际上受到状态改变影响的视图。 不用了,谢谢。

无论如何,在我提出这个问题之后,我意识到“解决”function是一种反模式。 它等待所有的决心,然后animation状态的变化。 这是完全错误的 – 你希望你的状态之间的过渡动​​画能够平行于你的数据加载,所以后者可以被前者掩盖。

例如,假设你有一个项目列表,点击其中一个隐藏列表,并在不同的视图中显示项目的细节。 如果我们对项目细节的asynchronous加载平均需要400毫秒,那么我们可以在大多数情况下通过在列表视图上有300毫秒的“离开”animation和300毫秒的“input”animation来掩盖负载在项目详细信息视图。 这样我们就可以为UI提供一个柔和的感觉,并且可以避免在大多数情况下显示一个微调。

但是,这要求我们同时启动asynchronous加载和状态更改animation。 如果我们使用“parsing”,那么整个asynchronousanimation在animation开始之前发生。 用户点击,看到一个微调,然后看到过渡animation。 整个状态变化需要〜1000ms,太慢了。

“解决”可能是caching不同视图之间的依赖关系的一种有用的方法,如果它有select不等待承诺的话,但是当前的行为总是在状态改变开始之前解决它们使得它几乎没有用。 应该避免涉及asynchronous加载的任何依赖性。

我真的应该停止使用resolve来加载一些数据,而是直接开始将它们加载到相应的控制器中? 这样,只要作业执行完毕,我就可以更新相应的视图,而且在视图中我想要的地方,而不是全局。

你可以使用一个在$routeChangeStart上侦听的指令,例如在触发时显示元素:

 app.directive('showDuringResolve', function($rootScope) { return { link: function(scope, element) { element.addClass('ng-hide'); var unregister = $rootScope.$on('$routeChangeStart', function() { element.removeClass('ng-hide'); }); scope.$on('$destroy', unregister); } }; }); 

然后,将其放在特定视图的加载器上,例如:

视图1:

 <div show-during-resolve class="alert alert-info"> <strong>Loading.</strong> Please hold. </div> 

查看2:

 <span show-during-resolve class="glyphicon glyphicon-refresh"></span> 

这个解决scheme(以及其他许多解决scheme)的问题是,如果您从外部网站浏览到其中一个路由,那么以前的ng-view模板将不会被加载,因此您的页面在parsing时可能只是空白。

这可以通过创build一个将作为后备加载器的指令来解决。 它将监听$routeChangeStart并且只有在没有以前的路由时才显示一个加载器。

一个基本的例子:

 app.directive('resolveLoader', function($rootScope, $timeout) { return { restrict: 'E', replace: true, template: '<div class="alert alert-success ng-hide"><strong>Welcome!</strong> Content is loading, please hold.</div>', link: function(scope, element) { $rootScope.$on('$routeChangeStart', function(event, currentRoute, previousRoute) { if (previousRoute) return; $timeout(function() { element.removeClass('ng-hide'); }); }); $rootScope.$on('$routeChangeSuccess', function() { element.addClass('ng-hide'); }); } }; }); 

回退加载器将放在ng-view的元素之外:

 <body> <resolve-loader></resolve-loader> <div ng-view class="fadein"></div> </body> 

演示这一切: http : //plnkr.co/edit/7clxvUtuDBKfNmUJdbL3?p=preview

我觉得这很整齐

 app.run(['$rootScope', '$state',function($rootScope, $state){ $rootScope.$on('$stateChangeStart',function(){ $rootScope.stateIsLoading = true; }); $rootScope.$on('$stateChangeSuccess',function(){ $rootScope.stateIsLoading = false; }); }]); 

然后再查看

 <div ng-show='stateIsLoading'> <strong>Loading.</strong> </div> 

为了进一步Pranay的答案,这是我是如何做到的。

JS:

 app.run(['$rootScope',function($rootScope){ $rootScope.stateIsLoading = false; $rootScope.$on('$routeChangeStart', function() { $rootScope.stateIsLoading = true; }); $rootScope.$on('$routeChangeSuccess', function() { $rootScope.stateIsLoading = false; }); $rootScope.$on('$routeChangeError', function() { //catch error }); }]); 

HTML

 <section ng-if="!stateIsLoading" ng-view></section> <section ng-if="stateIsLoading">Loading...</section> 

我迟了两年这个,是的这些其他的解决scheme的工作,但我觉得只是在这样一个运行块处理所有这一切比较容易

 .run(['$rootScope','$ionicLoading', function ($rootScope,$ionicLoading){ $rootScope.$on('loading:show', function () { $ionicLoading.show({ template:'Please wait..' }) }); $rootScope.$on('loading:hide', function () { $ionicLoading.hide(); }); $rootScope.$on('$stateChangeStart', function () { console.log('please wait...'); $rootScope.$broadcast('loading:show'); }); $rootScope.$on('$stateChangeSuccess', function () { console.log('done'); $rootScope.$broadcast('loading:hide'); }); }]) 

你不需要别的东西。 很容易吧。 这是一个在行动中的例子http://plnkr.co/edit/tggNzKlHMc9OwAnBq6eA?p=preview

在ui路由器1.0 $ stateChange *事件被弃用。 改用transition hook。 请参阅下面的迁移指南了解更多详情

https://ui-router.github.io/guide/ng1/migrate-to-1_0#state-change-events

“$ stateChangeStart”和“$ stateChangeSuccess”的问题是“$ rootScope.stateIsLoading”在返回上一个状态时不会刷新。 有没有解决方法? 我也用过:

  $rootScope.$on('$viewContentLoading', function(event){....}); 

  $rootScope.$on('$viewContentLoaded', function(event){....}); 

但也有同样的问题。