2017-09-22 72 views
5

我對我的角度應用使用了angular 1.6.5,並且遇到了一個非常奇怪的行爲。Angular沒有在ng-view上更新ng-class

我想要實現的是:當ngroute被改變時,我必須從當前視圖中刪除活動類,等待完成動畫,然後將活動類添加到新視圖。

我已經在配置中設置了應用和路由。

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>" 
     }); 
}); 

我在哪裏存儲的動畫的定時和視布爾值,指示可見性的服務:

app.service('animationProperties', function() { 
    this.animationTimings = { 
    views: 1000 
    }; 
    this.visibility = { 
    view : false 
    }; 
}); 

我有簡單的調試功能和一個onRouteChangeStart功能的一個主控制器,其應該從當前除去有源類視圖(通過使視圖知名度布爾值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等待離開動畫完成,然後刪除當前視圖(DONE()方法),並通過使能見度布爾真正再次進入新的觀點:

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

當切換頁面第一時間(導航),你會看到一切工作正常,但當第二次看視圖類沒有更新時,所以動畫不播放。在調試的時候,你可以清楚地看到可見性布爾值被正確更新,但離開視圖時的ng-class沒有得到更新。

您的幫助將非常感謝!

回答

1

引用自己從here

這是怎麼回事:

  1. 在一個$routeChangeStart,將更改(評估一次)的值會告訴ngClass從離開刪除active類視圖。
  2. 與此同時,$route開始準備輸入視圖,包括獲取其模板。
  3. 一切準備就緒後,會觸發$routeChangeSuccess事件,該事件表示ngView開始交換兩個視圖。
  4. 在交換過程中,ngView破壞了離開視圖的範圍,從這一點開始,範圍的觀察者停止......觀看。

所以,如果步驟1-4發生足夠快,離開的視圖的範圍必要的表達式爲ngClass評估,以去除active課前銷燬。第一次訪問路線時,動畫會起作用,因爲$route必須爲輸入視圖的模板發出服務器請求(這使得ngClass時間可以完成其工作)。但是,當您訪問以前訪問過的路線時,該模板已被緩存並且轉換速度很快。


您可以通過有意放慢模板檢索(甚至虛擬機轉向就足夠了)來解決此問題。例如:

​​

Updated plnkr 1

另一種方式來解決它,是爲了實現自己的,簡單的,同步的ngClass版本,讓類立即應用,之前離開的視圖的範圍銷燬。一個CRUD,這樣的指令的未優化,非生產就緒版本看起來是這樣的:

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動畫同步,然後設置標誌。
  • 通過設置標誌,觸發輸入視圖的相反CSS動畫。

對於初學者來說,爲什麼同時使用CSS和JS一個動畫?例如,你可以處理來自JS動畫的不透明度改變(假設你的實際設置更復雜,並且需要其他效果的JS動畫)。

或者你可以更輕鬆地處理輸入/輸出的淡出基於自動添加一個純CSS動畫/刪除ng-enter/ng-leave類(它只是4微小的CSS規則:笑臉:):

[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