AngularJS之Directive(三)


前言

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

【2】html:

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

此時的結果是四個帶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:"<h1>Hello<div ng-transclude></div></h1>",
        }
    });

【html】:

    <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):

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM