angular常見坑洞

詩&遠方發表於2015-03-06

由於版本不同,可能有些問題在某些版本下出現,某些版本下不出現.

指令不可平行(v1.3.2):

多個指令不能這樣一個接著一個排下去:

<div>
    <directive-one/>
    <directive-two/>
    <directive-three/>
</div>    

這樣會導致的結果就是,只能讀取<directive-one/>,後面的兩個指令被自動無視掉~~~憑空消失鳥~~~

解決辦法: 每個指令放在一個div裡

<div>
    <directive-one/>
</div>  
<div>
    <directive-two/>
</div>  
<div>
    <directive-three/>
</div>  

還有個解決辦法,把指令的restrict指定為EA,然後不要使用<directive/>這種形式,而是使用<div directive>這種形式.

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

變數名和模組名不能相同(v1.3.2):

如下這樣會報錯,無法執行:

var model = angular.module('model',[]);

玫紅色和墨綠色的兩個名字不能相同,這個問題很少出現,應該是不會的.但是有一次確實遇到了...

解決辦法: 不說了...

 

指令模板裡面不能用出現指令名作為類名(v1.3.2):

比如一個指令叫 <menu-bar/>

那麼,指令的模板裡面,我不能再有 <div class="menu-bar">

如果遇到這種情況,它會報錯: $compile:multidir

解決辦法: 

1.換不同的名字

2.指令的restrict中去掉C值

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 

e.stopPropagation()阻止不了a連結的預設跳轉事件(v1.3.2): 

比如這樣一段程式碼:

  <a href="http://www.baidu.com">
      <span ng-click="do($event)"></span>
  </a>
$scope.do = function(e){
      e.stopPropagation();              
}    

這裡我已經給do函式新增了阻止冒泡,但是a連結的跳轉還是會觸發的.

解決辦法: 使用 e.preventDefault();

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 

通過link函式中的iele來給元素繫結事件和通過ng-click(ng-...)等繫結事件的差異性(v1.3.2): 

這個其實不是坑,只是使用上的一個注意點.什麼意思呢? 

就是說,指令的link屬性第二個引數'iele',有時候我們可以通過$(iele).bind(),直接使用jq來給元素繫結事件:

link: function(scope,iele){
     $(iele).find('input').bind('focus',function(){
          scope.flag = true       
     })
}

另外,我們也可以在html中使用 ng-click(ng-event...)等來繫結事件:

<input ng-focus="changeFlag()">
link: function(scope,iele){
     scope.changeFlag = function(){
           scope.flag = true
     }
}

那麼什麼時候使用第一種,什麼時候使用第二種呢?

是這樣的,如果事件處理程式裡,改變了當前scope下的屬性值,也就是說,資料發生了改變,這個時候使用第二種,如果事件處理程式裡,僅僅改變檢視的顯示(並非通過資料的改變來改變檢視的顯示),這個時候使用第一種.

為什麼呢? 因為使用第二種,是ng自己繫結的事件,在執行事件以後,ng會自動進行髒值檢測($digest),而自己繫結的事件,ng是不會檢測的(雖然我做的過程中發現有時候也會檢測...⊙﹏⊙b汗),這樣,scope下資料模型發生改變,是不會被檢測到的,需要手動去呼叫$digest,雖然也可以實現,但是就不符合ng的設計模式了.

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 

給指令新增控制器時候的scope問題(v1.3.2):

這個坑很大...一不小心陷入萬丈深淵...

比如有一個指令:

<directive/>

指令是這樣定義的:

module.directive('directive',function(){
      return {
            restrict:'E',
            replace:true,
            templateUrl:'index.html'
      }   
})

然後index.html是這樣的:

<div ng-controller="controllerOne">
    ...
</div>

定義控制器:

module.controller('controllOne',function($scope){
    $scope.a = 'a'
})

這樣,正常的理解就是directive指令這個div,使用controllerOne來管理,它的scope就是controllerOne裡面的$scope.

但是事實不是這樣的,用這種方式定義的controller,$scope並非是一個單獨的繼承了父scope的scope,而是直接繫結在了根scope上!

解決辦法: 在指令元素上繫結ng-controller屬性,而不是指令的html模板上:

<directive ng-controller="controllerOne"/>

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 

使用ui-router路由切換時狀態的事件(ui-router.min.js  v0.2.12)

ui-router狀態改變時會觸發$stateChangeStart,$stateChangeSuccess,$viewContentLoading,$viewContentLoaded這些事件,但是這些事件不能繫結在狀態的controller屬性的控制器裡:

$stateProvider.state('index',{
        url:'/index',
        resolve:{
            rsv:'aService'
        },
        controller:function($rootScope,$scope,rsv){
            $scope.username = rsv.getName();
            $rootScope.$on('$viewContentLoading',function(event, viewConfig){
                alert('檢視開始渲染');
            });
            $rootScope.$on('$viewContentLoaded',function(){
                alert('檢視渲染完畢');
            })
        },
        templateUrl:'./tpls/login.html'
    });

這樣做,每次進入index狀態,都會例項化一個控制器,都會繫結一次事件,這樣,$viewContentLoading和$viewContentLoaded事件會越來越多.

解決辦法: 在外層的控制器的$rootScope裡繫結事件.

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 

date過濾器:

使用date過濾器過濾時間時,時間的值如果是數字或者字串數字,這個數字不是時間戳,而是當前時間毫秒數.也就是時間戳*1000 

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 

使用ui-router路由的$urlRouterProvider無效(ui-router.min.js  v0.2.12)

定義了一個路由,然後通過$urlRouteProvider來定義一個重定向: 當匹配到'/'的時候,重定向到'/all'

flightApp.config(function($stateProvider,$locationProvider,$urlRouterProvider){
    $locationProvider.html5Mode(true).hashPrefix('!');

    $stateProvider.state('index',{
        url:'/:date',
        templateUrl:'tpls/flights.html',
        resolve:{
            'filterFlights':function($http,$stateParams){
                return $http({
                    method:'get',
                    url:'cache/flights_'+($stateParams.date || 'all')+'.json'
                });
            }
        },
        controller: 'fligntsControll'
    });

$urlRouterProvider.when('/','/all');
});

但是這個重定向並沒有實現,也沒有任何報錯.原因不詳.

解決辦法:修改順序,把$urlRouterProvider.when()這段程式碼移到$stateProvider.state()之前

flightApp.config(function($stateProvider,$locationProvider,$urlRouterProvider){
    $locationProvider.html5Mode(true).hashPrefix('!');

    $urlRouterProvider.when('/','/all');

    $stateProvider.state('index',{
        url:'/:date',
        templateUrl:'tpls/flights.html',
        resolve:{
            'filterFlights':function($http,$stateParams){
                return $http({
                    method:'get',
                    url:'cache/flights_'+($stateParams.date || 'all')+'.json'
                });
            }
        },
        controller: 'fligntsControll'
    });
});

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 

 

相關文章