AngularJS核心之Directive

cnnbull發表於2021-09-09

前言

angular核心部分如下圖幾大塊,最重要的莫過於指令這一部分,本文將重點講解指令這一部分,後續筆者將透過陸續的學習來敘述其他如:factory、service等,若有敘述錯誤之處,歡迎各位指正以及批評。本文將透過一些例項來進行敘述。

圖片描述

話題 

restrict以及replace

在sublimeText中安裝angular外掛之後,我們需要建立指令時此時將自動出現如下定義:所以我們將重點放在如下各個變數的定義。

.directive('', ['', function(){
       // Runs during compile
       return {
           // name: '',
           // priority: 1,
           // terminal: true,
           // scope: {}, // {} = isolate, true = child, false/undefined = no change
           // controller: function($scope, $element, $attrs, $transclude) {},
           // require: 'ngModel', // Array = multiple requires, ? = optional, ^ = check parent elements
           // restrict: 'A', // E = Element, A = Attribute, C = Class, M = Comment
           // template: '',
           // templateUrl: '',
           // replace: true,
           // transclude: true,
           // compile: function(tElement, tAttrs, function transclude(function(scope, cloneLinkingFn){ return function linking(scope, elm, attrs){}})),
           link: function($scope, iElm, iAttrs, controller) {
               
           }
       };
   }]);


首先我們只需要知道一個屬性【restrict】,意思是替換的是什麼,【E】:元素,【A】:屬性,【C】:類名,【M】:註釋。template(模板)自然就不用說了。下面我們來看一個有關指令最簡單的例子。

【1】指令碼:



   var app = angular.module('app', []);
   app.directive("hello",function(){
       return{
           restrict:"EACM",
           template:"

Hello

"
       }
   });


【2】html:

         
    
         

         <!-- directive:hello --&gt

此時的結果是四個帶h1標籤的Hello嗎?顯然不是,如下:

圖片描述

不是說好的將restrict的模式設定為【EACM】,理論上應該是顯示四個,結果卻不是。即使你設定了四個也只會顯示三個,而註釋不會顯示,此時要設定另外一個屬性即【replace:true】才會顯示四個註釋。同時也需要注意,在註釋中的hello和後面的--之間要有間隔,你可以試試。

transclude 

當我們替換的元素裡面可能還巢狀者其他元素,而其他元素裡面有內容,我們不希望被覆蓋,此時就需要將transclude設定為true並將要應用的元素標記為ng-transclude。如下:

【指令碼】:



   var app = angular.module('app', []);
   app.directive("hello",function(){
       return{
           restrict:"EACM",
           transclude:true,
           template:"

Hello

",
       }
   });


【html】:

            
       
部落格園,你好
         

結果如下:

圖片描述

tepmlateUrl

在實際開發中用template形式來給出模板似乎不太友好,一旦替換的內容比較多那麼顯得程式碼比較凌亂,此時我們就要用到templateUrl,將模板單獨寫在一個頁面即可。這個就不用說了,在這個內容不得不說的是模板的快取。 

【指令碼】:



   var app = angular.module('app', []);
   app.run(function($templateCache){
       $templateCache.put("hello.html","

hello cnblogs

")
   });
   app.directive("hello",function($templateCache){
       return{
           restrict:"AE",
           template:$templateCache.get("hello.html"),
           replace:true
       };
   });


【html】:

結果如下:

 圖片描述

scope

在接觸這個屬性之前我們首先來看看一個例子。

【指令碼】:



   var app = angular.module('app', []);
   app.directive("hello",function(){
       return{
           restrict:"AE",
           template:'
{{test}}
',
           replace:true
       };
   });


【html】:

    
         
         

我們來瞧瞧結果:

圖片描述

我們將滑鼠放在第一個文字框輸入xpy0928,下面兩個同樣也發生相應的改變,我們再試試將滑鼠聚焦於第二個看看其他兩個的改變如何:

圖片描述

由上知,同樣如此,貌似三個文字框的作用域是一樣的,一變都變,相互影響。在指令中,當我們需要保持各自的作用域時,此時就需要【scope】屬性,並設定為true。我們再來試試

圖片描述

require 

【指令與頁面上已定義控制器進行互動】

在開始這個話題之前我們先看看指令與已定義的控制器如何進行互動?【注意是在頁面上已定義的控制器】

【指令碼】:

圖片描述


   var app = angular.module('app', []);
   app.controller("ctrl",["$scope",function($scope){
       $scope.win = function(){
           alert("你贏了");
       }
   }])
   app.directive("lay",function(){
       return{
           restrict:"AE",
           scope:true,
           template:'
點選我,有驚喜哦
',
           replace:true,
           link:function(scope,elment,attr){
               elment.on("click",function(){
                   scope.win();
               })
           }
       };
   });

圖片描述

【html】:

    
                             

圖片描述

對於頁面中已定義的控制器,指令為與其進行互動直接透過link上的scope來獲取該控制器上的APi即可。

【指令與指令上控制器進行互動】

此時就需要用到require,此屬性的作用是指令與指令之間的互動,說的更加具體一點就是與其他指令中控制器之間的互動。在指令中獲取其他指令的控制器要用到link函式的第四個引數,link函式的前三個引數還是非常容易理解,不再敘述。那麼是怎樣在當前指令去獲取該控制器呢?這時就需要用到require屬性。

(1)require的值用?、^、或者?^修飾。

(2)如果不用任何修飾,則在當前指令中進行查詢控制器。

(3)如果用^修飾,則在當前指令的父指令進行查詢控制器,若未找到,則會丟擲異常。

(4)如果用?修飾,則說明在當前指令中未找到控制器,此時將以null作為第四個引數。

(5)如果需要互動多個指令,則以陣列形式給出,如:[^?a,^?b]。

鑑於此,為了不丟擲異常,我們一般以^?來進行修飾。

就上面解釋,我們來看一個例子,如下:

【指令碼】:



   var app = angular.module('app', []);
   app.directive('customdirective', function(){
       return {    
           controller: function($scope, $element, $attrs, $transclude) {
               var self = this;
               $scope.count = 0;
               self.add = function(){
                   $scope.$apply(function(){
                       $scope.count++;
                   })
               }
           },        
           restrict: 'E',
       };
   }).directive('childirective', function(){
       return {
           require: '^customdirective',
           restrict: 'E',
           template: '',
           replace: true,
           link: function($scope, iElm, iAttrs, controller) {        
               angular.element(document.getElementById("add")).on("click",controller.add);                
           }
       };
   })


【html】:



   
次數:{{count}}

   

   

圖片描述

對於指令上的link與指令上的controller的何時使用,我們可以這樣概括:當一個指令上想向外部暴露這個指令時,此時利用controller進行暴露,而其他指令需要利用指令時,透過屬性require和link上的第四個引數進行獲取暴露指令的APi,否則的話我們不需要第四個引數。

那麼問題來了,指令的作用到底是什麼呢?

假如我們有幾個控制器都需要用到相同指令但是對應不同事件時,此時難道需要定義不同的指令嗎?答案肯定很顯然不是,指令說到底就是為了【複用】。下面我們繼續來看一個例子。

【指令碼】:


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

   app.controller("first",["$scope",function($scope){
       $scope.first = function(){
           alert("第一個控制器函式");
       }
   }])

   app.controller("second",["$scope",function($scope){
       $scope.second = function(){
           alert("第二個控制器函式");
       }
   }])

   app.directive('lay', function(){
       return{
             restrict:"AE",
             link:function(scope,element,attr){
                 element.on("click",function(){
                     scope.$apply(attr.loader);
                 })
             }
       };
   });
複製程式碼


【html】:




   第一個控制器




   第二個控制器


 圖片描述

 當需要複用指令時,可以透過獲取指令上屬性對應的方法,最終利用apply方法應用到對應的控制器中。

結語

在這裡我們稍微詳細的敘述了指令中有關屬性的用法,對於一些原理性的東西,畢竟不是做前端的,所以沒有做過多的探討。下面我們最後以一個例項來結束本文。

透過指令來使未驗證透過的文字框聚焦。

【指令碼】:


    var app = angular.module('app', []);
   app.controller('ctrl', function ($scope, $location, $rootScope) {  
   })
   app.directive("parentDirective", function () {  
   return {  
       restrict: 'A',  
       require: ['form'],  
       controller: function () {  
           // nothing here  
       },  
       link: function (scope, ele, attrs, controllers) {  
           var formCtrl = controllers[0];  
       }  
   };  
   }).directive('input', function () {  
   return {  
       restrict: 'E',  
       priority: -1000,  
       require: ['^?parentDirective', '^?angularValidator'],  
       link: function (scope, elm, attr, ctrl) {  
           if (!ctrl) {  
               return;  
           }  
 
           elm.on('focus', function () {  
               elm.addClass('apply-focus');  
 
               scope.$apply(function () {  
                   ctrl.hasFocus = true;  
               });  
           });  
 
           elm.on('blur', function () {  
               elm.removeClass('apply-focus');  
               elm.addClass('apply-visited');  
 
               scope.$apply(function () {  
                   ctrl.hasFocus = true;  
                   ctrl.hasVisited = true;  
 
               });  
           });  
 
       }  
   };  
});


【html】:


 
           
                              
                   
                       
                                                  
                       
                                                  
                       
                                                  
                       
                                                  
                   
               
               
                   
                       
                                                  
                       
                                                  
                   
               
              
       
   複製程式碼

效果(1):

圖片描述

效果(2):

圖片描述

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2524/viewspace-2808788/,如需轉載,請註明出處,否則將追究法律責任。

相關文章