我在我的 Angular 应用程序中使用angular 1.6.5,遇到了一个非常奇怪的行为。

我要实现的是:更改ngroute时,必须从当前 View 中删除事件类,等待离开动画完成,然后将事件类添加到新 View 中。

我已经在配置中设置了应用和路由。

var app = angular.module('app', ['ngAnimate', 'ngRoute']);

app.config(function ($routeProvider) {
    $routeProvider
      .when('/', {
        templateUrl:"home.html",
        reloadOnSearch:false
      })
      .when('/about-us', {
        templateUrl:"about.html",
        reloadOnSearch:false
      })
      .when('/contact', {
        templateUrl:"contact.html",
        reloadOnSearch:false
      })
      .otherwise({
          template : "<h1>None</h1><p>Nothing has been selected</p>"
      });
});

我有一项服务,用于存储动画时间和 bool 值,以指示 View 的可见性:
app.service('animationProperties', function () {
  this.animationTimings = {
    views: 1000
  };
  this.visibility = {
    view : false
  };
});

我有一个具有简单调试功能的主 Controller 和一个onRouteChangeStart函数,应从当前 View 中删除事件类(通过将 View 可见性 bool 值设置为false):
app.controller('MainCtrl', function ($scope, $window, $location,
                                     animationProperties) {

  $scope.animationProperties = animationProperties;

  $scope.$on('$routeChangeStart',function () {
    animationProperties.visibility.view = false;
  });

  $scope.toggleActive = function(){
    $scope.animationProperties.visibility.view = !$scope.animationProperties.visibility.view;
  }
});

最后,ngAnimate等待离开动画完成,然后删除当前 View (使用done()方法),并通过将可见性 bool 值设为true来再次进入新 View :
app.animation('.view', function($timeout, animationProperties) {
  return {
    enter: function(element, done) {
      $timeout(function () {
        animationProperties.visibility.view = true;
        $timeout(function () {
          done();
        }, animationProperties.animationTimings.views);//Wait to enter
      },animationProperties.animationTimings.views); //Wait for leave function
    },
    leave: function(element, done) {
      $timeout(function () {
        done();
      }, animationProperties.animationTimings.views);
    }
  }
});

这是plunker

第一次(从导航)切换页面时,您会看到一切正常,但是第二次进入页面时, View 类未更新,因此不会播放动画。在调试时,您可以清楚地看到可见性 bool 值已正确更新,但是离开 View 时的ng-class不会得到更新。

您的帮助将不胜感激!!!

最佳答案

here引用自己:

这是怎么回事:

  • $routeChangeStart上,更改(一旦求值)将告诉ngClass从离开 View 中删除active类的值。
  • 同时,$route开始准备进入的 View ,包括获取其模板。
  • 一切准备就绪后,它将触发$routeChangeSuccess事件,该事件指示ngView开始交换两个 View 。
  • 在交换过程中,ngView破坏了离开 View 的范围,从此以后,该范围的观察者就不再受到监视。

  • 因此,如果步骤1-4发生得足够快,则在评估必要的ngClass表达式以删除active类之前,将离开 View 的范围被破坏。第一次访问路线时,动画会起作用,因为$route必须向输入 View 的模板发出服务器请求(这使ngClass有时间完成其工作)。但是,当您访问以前访问的路线时,模板已经被缓存,并且转换速度很快。

    您可以通过故意减慢模板检索的速度来解决此问题(即使VM转弯就足够了)。例如:
    app.decorator('$templateRequest', ($delegate, $timeout) => {
      const $templateRequest = (...args) => $delegate(...args).
        then(tmpl => $timeout().then(() => tmpl));
      Object.defineProperty($templateRequest, 'totalPendingRequests', {
        get: () => $delegate.totalPendingRequests,
        set: nv => $delegate.totalPendingRequests = nv,
      });
      return $templateRequest;
    });
    

    (Updated plnkr 1)

    解决该问题的另一种方法是实现自己的ngClass的简化同步版本,以便在销毁离开 View 的作用域之前立即应用类。这种指令的原始的,未经优化的,非生产就绪的版本可能看起来像这样:
    app.directive('myClass', () => (scope, elem, attrs) => {
      scope.$watchCollection(attrs.myClass, newValue => {
        Object.keys(newValue).forEach(c => {
          if (newValue[c]) {
            elem.addClass(c);
          } else {
            elem.removeClass(c);
          }
        });
      });
    });
    

    (Updated plnkr 2)

    话虽这么说,您的设置似乎很奇怪:
  • 监听事件($routeChangeStart)。
  • 设置一个触发animationProperties.visibility.views删除类的标志(ngClass)。
  • 删除类,触发CSS动画。
  • 同时,让一个自定义JavaScript动画(animation('.view'))与CSS动画进行自我同步,然后将标记设置回去。
  • 通过将标志设置回去,为进入的 View 触发相反的CSS动画。

  • 😕

    首先,为什么同时使用CSS和JS动画?例如,您可以处理JS动画中的不透明度更改(假设您的实际设置更加复杂,并且需要JS动画才能具有其他效果)。

    或者,您可以基于自动添加/删除的ng-enter/ng-leave类的纯CSS动画,更轻松地处理淡入/淡出(这只是4条小小的CSS规则:smiley :):
    [ng-view].ng-enter {
      /* Wait for the leaving view to...leave, then start transitioning in. */
      transition: opacity 1s ease 1s;
    }
    
    [ng-view].ng-leave {
      /* Start transitioning out. */
      transition: opacity 1s ease;
    }
    
    [ng-view].ng-enter,
    [ng-view].ng-leave.ng-leave-active {
      /*
       * At the beginning of the entering animation and
       * at the end of the leaving animation,
       * the view must be fully invisible.
       */
      opacity: 0;
    }
    
    [ng-view].ng-enter.ng-enter-active,
    [ng-view].ng-leave {
      /*
       * At the end of the entering animation and
       * at the beginning of the leaving animation,
       * the view must be fully visible.
       */
      opacity: 1;
    }
    

    (Updated plnkr 3)

    关于javascript - Angular不更新ng-view上的ng-class,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/46365402/

    10-11 23:31
    查看更多