angularjs - 在 ui-router 解析期间应用加载微调器

标签 angularjs web-applications angular-ui-router single-page-application

$routeProvider

resolve 属性允许在渲染相应 View 之前执行一些作业。

如果我想在执行这些作业时显示微调器以提高用户体验,该怎么办?
事实上,否则用户会感觉应用程序已被阻止,因为在某些毫秒 > 600 毫秒内没有显示任何 View 元素。

当然,有一种方法可以定义一个全局 div 元素在当前 View 之外来显示,以便显示微调器,这要归功于 $ scope.$rootChangeStart 函数。
但我不想隐藏整个页面,而中间只有一个糟糕的旋转器。
我希望我的网络应用程序的某些页面在加载显示方式方面有所不同。

我发现 this interesting post 包含我上面描述的确切问题:

That approach results in a horrible UI experience. The user clicks on a button to refresh a list or something, and the entire screen gets blanketed in a generic spinner because the library has no way of showing a spinner just for the view(s) that are actually affected by the state change. No thanks.

In any case, after I filed this issue, I realised that the "resolve" feature is an anti-pattern. It waits for all the promises to resolve then animates the state change. This is completely wrong - you want your transition animations between states to run parallel to your data loads, so that the latter can be covered up by the former.

For example, imagine your have a list of items, and clicking on one of them hides the list and shows the item's details in a different view. If we have an async load for the item details that takes, on average, 400ms, then we can cover up the load almost entirely in most cases by having a 300ms "leave" animation on the list view, and a 300ms "enter" animation on the item details view. That way we provide a slicker feel to the UI and can avoid showing a spinner at all in most cases.

However, this requires that we initiate the async load and the state change animation at the same moment. If we use "resolve", then the entire async animation happens before the animation starts. The user clicks, sees a spinner, then sees the transition animation. The whole state change will take ~1000ms, which is too slow.

"Resolve" could be a useful way to cache dependencies between different views if it had the option not to wait on promises, but the current behaviour, of always resolving them before the state change starts makes it almost useless, IMO. It should be avoided for any dependencies that involve async loads.

我真的应该停止使用 resolve 加载一些数据,而是开始直接将它们加载到相应的 Controller 中吗?这样我只要执行作业并且在 View 中我想要的位置就可以更新相应的 View ,而不是全局。

最佳答案

您可以使用监听 $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);
    }
  };
});

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

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

此解决方案(以及与此相关的许多其他解决方案)的问题是,如果您从外部站点浏览到其中一个路由,则不会加载以前的 ng-view 模板,因此您的页面在执行期间可能只是空白解决。

这可以通过创建一个充当后备加载程序的指令来解决。它将监听 $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

关于angularjs - 在 ui-router 解析期间应用加载微调器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24200909/

相关文章:

Angularjs 重用计算值

performance - Web 应用程序性能基准的建议

angularjs - 如何在其他表单成功提交后提交第二个表单

javascript - 从 ng-swipe 事件模拟 ui-sref 的首选方法是什么?

javascript - 使用 AngularJS 混合完全渲染和部分渲染的页面

javascript - Angular Directive(指令)不应用样式

javascript - 提交时的表单验证 - angularjs 1.5 - 当字段 $pristine 时 $invalid

angularjs - 了解指令定义的 transinclude 选项?

java - Weblogic返回以0000开头的http响应

html - Blackberry 的 Webapp 开发工具