一尘不染

在ui路由器解析期间应用加载微调器

angularjs

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

如果我想在执行这些作业时显示微调框以增加用户体验怎么办?
确实,否则,用户会感觉到应用程序已被阻止,因为例如在大于600的毫秒内没有显示任何视图元素。

当然,由于该功能,因此可以 从当前视图中定义* 要显示的全局div元素,以便显示微调器。
但是我不想只在中间放置一个糟糕的微调器来隐藏整个页面。 我希望Webapp的某些页面在显示加载方式方面有所不同。
$scope.$rootChangeStart
***

我碰到了一个有趣的帖子,其中包含我上面所述的确切问题:

这种方法导致可怕的UI体验。用户单击按钮以刷新列表或其他内容,并且整个屏幕都覆盖在通用微调器中,因为库无法仅针对实际上受状态更改影响的视图显示微调器。不用了,谢谢。

无论如何,在提出此问题之后,我意识到“解决”功能是一种反模式。它等待所有承诺解决,然后为状态更改添加动画效果。这是完全错误的-
您希望状态之间的过渡动​​画与数据加载并行运行,以便后者可以被前者掩盖。

例如,假设您有一个项目列表,然后单击其中的一个将隐藏该列表,并在其他视图中显示该项目的详细信息。如果我们对项目详细信息的异步​​加载平均需要400毫秒,那么在大多数情况下,我们可以通过在列表视图上放置300毫秒的“离开”动画和300毫秒的“输入”动画来几乎完全覆盖负载在项目详细信息视图上。这样,我们为UI提供了一种流畅的感觉,并且在大多数情况下可以完全避免显示微调器。

但是,这要求我们同时启动异步加载和状态更改动画。如果使用“解决”,则整个异步动画都会在动画开始之前发生。用户单击,看到一个微调器,然后看到过渡动画。整个状态更改将花费〜1000ms,这太慢了。

如果可以选择不等待promise,“
resolve”可能是一种缓存不同视图之间的依赖关系的有用方法,但是当前的行为(总是在状态更改开始之前对其进行解决)使其几乎无用,IMO。对于涉及异步负载的任何依赖关系,都应避免使用。

我是否应该真正停止使用resolve加载一些数据,而是直接将它们直接加载到相应的控制器中?这样我就可以更新相应的视图,只要该作业已执行且在视图中所需的位置即可,而不是全局。


阅读 203

收藏
2020-07-04

共1个答案

一尘不染

您可以使用侦听指令,$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>

此解决方案(以及与此相关的许多其他解决方案)的问题在于,如果您从外部站点浏览到其中一个路由,则不会加载以前的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

2020-07-04