javascript - Angular 未在 ng-view 上更新 ng-class

标签 javascript angularjs ng-animate ng-view

我在我的 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 的值删除 active从离开的 Angular 上课。
  • 同时,$route开始准备进入 View ,包括获取它的模板。
  • 一旦一切准备就绪,它就会触发 $routeChangeSuccess事件,它发出信号 ngView开始交换两个 View 。
  • 在交换过程中,ngView破坏离开 View 的作用域,从那时起作用域的观察者不再被……观察。

  • 因此,如果步骤 1-4 发生得足够快,则在为 ngClass 评估必要的表达式之前,将破坏离开 View 的范围。删除 active类(class)。第一次访问路线时,动画有效,因为 $route必须对进入 View 的模板发出服务器请求(这给了ngClass 时间来完成它的工作)。但是,当您访问之前访问过的路线时,模板已经被缓存并且过渡很快。

    您可以通过故意减慢模板检索速度来解决此问题(即使是虚拟机轮次也足够了)。例如:
    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 动画来获得其他效果)。

    或者,您可以使用基于自动添加/删除的纯 CSS 动画更轻松地处理淡入/淡出 ng-enter/ng-leave类(它只是 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/

    相关文章:

    javascript - Mongoose 中的回调函数

    javascript - 将 UTC 时间戳解析为本地时间,忽略时区

    javascript - 在 Jade View 上获取 'Syntax Error'

    javascript - AngularJS路由: unnecessary params in url

    javascript - 带有 ng-animate 的 ng-show 无法正常工作

    javascript - 不进行异步调用的 CommonJS 模块加载器

    javascript - 从函数调用 Controller 并向其传递 URL 编码的参数

    angularjs - Angular 1.x $q 到 Angular 2.0 beta

    javascript - Angular 交错动画自定义指令

    angularjs - 重新排序数组时如何使用angular-animate触发ng-move?