AngularJS之Directive(三)

前言

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

話題 

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:"<h1>Hello</h1>"
        }
    });

【2】html:app

    <hello></hello> 
    <div hello></div>
    <p class="hello"></p>
    <!-- directive:hello -->

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

不是說好的將restrict的模式設置爲【EACM】,理論上應該是顯示四個,結果卻不是。即便你設置了四個也只會顯示三個,而註釋不會顯示,此時要設置另一個屬性即【replace:true】纔會顯示四個註釋。同時也須要注意,在註釋中的hello和後面的--之間要有間隔,你能夠試試。函數

transclude 

當咱們替換的元素裏面可能還嵌套者其餘元素,而其餘元素裏面有內容,咱們不但願被覆蓋,此時就須要將transclude設置爲true並將要應用的元素標記爲ng-transclude。以下:學習

【腳本】:ui

    var app = angular.module('app', []);
    app.directive("hello",function(){
        return{
            restrict:"EACM",
            transclude:true,
            template:"<h1>Hello<div ng-transclude></div></h1>",
        }
    });

【html】:this

    <hello>
        <div>博客園,你好</div>
    </hello>

結果以下:

tepmlateUrl

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

【腳本】:

    var app = angular.module('app', []);
    app.run(function($templateCache){
        $templateCache.put("hello.html","<h1>hello cnblogs</h1>")
    });
    app.directive("hello",function($templateCache){
        return{
            restrict:"AE",
            template:$templateCache.get("hello.html"),
            replace:true
        };
    });

【html】:

<hello></hello>

結果以下:

 

scope

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

【腳本】:

    var app = angular.module('app', []);
    app.directive("hello",function(){
        return{
            restrict:"AE",
            template:'<div><input type="text" ng-model="test"/>{{test}}</div>',
            replace:true
        };
    });

【html】:

    <hello></hello><br/>
    <hello></hello><br/>
    <hello></hello>

咱們來瞧瞧結果:

咱們將鼠標放在第一個文本框輸入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:'<div>點擊我,有驚喜哦</div>',
            replace:true,
            link:function(scope,elment,attr){
                elment.on("click",function(){
                    scope.win();
                })
            }
        };
    });

【html】:

    <div ng-controller="ctrl" style="background-color:orange">
        <lay></lay>
    </div>

對於頁面中已定義的控制器,指令爲與其進行交互直接經過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: '<button id="add">點擊增長1</button>',
            replace: true,
            link: function($scope, iElm, iAttrs, controller) {        
                angular.element(document.getElementById("add")).on("click",controller.add);                
            }
        };
    })

【html】:

<customdirective>
    <div>次數:{{count}} </div> 
    <br/>
    <childirective></childirective>
</customdirective>

對於指令上的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】:

<div ng-controller="first">
    <lay loader="first()">第一個控制器</lay>
</div>
<br/>
<div ng-controller="second">
    <lay loader="second()">第二個控制器</lay>
</div>

 

 當須要複用指令時,能夠經過獲取指令上屬性對應的方法,最終利用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】:

 <form  ng-controller="ctrl" novalidate angular-validator >  
        <div class="gloabl-form-content">  
              
            <div class="row">  
                <div class="col yellow-divider">  
                    <div class="col-first">  
                        <label><span  style="color:red;">*</span>姓名</label>  
                    </div>  
                    <div class="col-second">  
                        <input name="name"  
                            type="text"  
                            ng-model="profile.name"  
                            validate-on="blur"  
                            ng-pattern="/^[ a-zA-Z]*$/"  
                            required  
                            required-message="'請輸入姓名.'"  
                            ng-message="'不能輸入數字'"  
                            maxlength="100" />  
                    </div>  

                    <div class="col-third">  
                        <label>住址</label>  
                    </div>  
                    <div class="col-four">  
                        <input name="addr" type="text" ng-model="profile.addr"  
                            validate-on="blur"  
                            ng-pattern="/^[ a-zA-Z]*$/"  
                            invalid-message="'不能輸入數字'"  
                            maxlength="100" />  
                    </div>  
                </div>  
            </div>  
            <div class="row">  
                <div class="col yellow-divider">  
                    <div class="col-third">  
                        <label><span  style="color: red;">*</span>手機號碼</label>  
                    </div>  
                    <div class="col-four">  
                        <input type="text"  
                            ng-model="customer.number"  
                            validate-on="blur"  
                            ng-pattern="/^[ 0-9.]*$/"  
                            required  
                            required-message="'請輸入手機號碼'"  
                            invalid-message="'只能輸入數字'" />  
                    </div>  
                </div>  
            </div>  
  
        </div>  
    </form>  

效果(1):

效果(2):

【擦,不行,快凍成傻逼了,手凍僵了,不能寫了,就到這裏諾。。。。。。。。。。】

相關文章
相關標籤/搜索