1. 程式人生 > >自定義指令的各種屬性詳解

自定義指令的各種屬性詳解

【一】 自定義指令的兩種方式

           1. 通過 module.directive(name,directiveFactory) 定義 , 如:        

         (function() {
           angular.module('starter')
             .directive('myCustomer', function() {
                return {
                   restrict: 'E',
                   templateUrl: 'directiveTest/my-customer.html'
            };
           })
          })()

           2. 注入 $compileProvider ,通過 $compileProvide.directive() 定義 , 如:

       var myApp = angular.module('myApp', [], ['$compileProvider',function ($compileProvider) {
         $compileProvider.directive('customTags',function(){
          return {
            restrict:'ECAM',
            template:'<div>custom-tags-html</div>',
            replace:false
          }
        });
      }])

【二】 restrict 、 template 、 replace、templateUrl屬性

      var myApp = angular.module('myApp', [], ['$compileProvider',function ($compileProvider) {
       // 如果指令的名字為xxx-yyy 在設定指令的名字時應為 xxxYyy 駝峰式命名法
       $compileProvider.directive('customTags',function(){
         return {
            restrict:'ECAM',
            template:'<div>custom-tags-html</div>',
            replace:false,
            // templateUrl :載入模板所要使用的URL
            //replace :如果為true 則替換指令所在的元素,如果為false 或者不指定,則把當前指令追加到所在元素的內部


            //restrict :指令在模板中的使用方式
            //可以4種風格任意組合,如果忽略restrict,預設為A
            // E : 風格為 元素  (作為標籤名)      使用方式: <custom-tags>1212</custom-tags>
            // C: 風格為 樣式類                   使用方式: <div class="custom-tags"> </div>
            // A : 風格為 屬性                    使用方式: <div custom-tags> </div>
            // M : 風格為 註釋


            // 注意:當有兩個directive的時候 只能有一個template,否則會報錯
         }
        });
    }])
【三】transclude、priority、terminal 屬性

           priority : 設定指令在模板中的執行順序,順序是相對於其他元素上的指令而言,預設為0,從大到小的順序一次執行

           terminal : 是否以當前指令的權重為結束界限。如果這個值設定為true,則節點中權重小於當前指令的其他指令不會被執行。相同權重的會執行 

    .directive('customTags', function () {
        return {
            restrict: 'ECAM',
            template:'<div>新資料 <span ng-transclude></span></div>',
            replace: true,
            transclude:true
            //transclude:為true時,指令元素中的原來的子節點移動到一個新模板內部(移動到的位置通過ng-transclude確定)
            //priority 設定優先順序
        }
    })

    .directive('customTags2', function () {
        return {
            restrict: 'ECAM',
            template:'<div>2</div>',
            replace: true,
            priority:0
        }
    })
    .directive('customTags3', function () {
        return {
            restrict: 'ECAM',
            template:'<div>3</div>',
            replace: true,
            priority: 1,
            // terminal 為true 時 priority 小於當前指令的priority的directive 都不會執行
            terminal:true
        }
    })
【四】 compile 和 link 屬性

Angularjs 指令編譯三個階段

1.標準瀏覽器API轉化
    將html 轉化成dom ,所以自定義的html 標籤必須符合html 的格式
2.Angular compile
    搜尋匹配 directive ,按照priority排序,並執行directive上的compile 方法
3.Angular link
     執行directive上的link 方法,進行 scope繫結及事件繫結
   link 函式負責在模型和檢視之間進行動態關聯

     .directive('customTags',function(){
        return {
            restrict : 'ECAM',
            template : '<div>{{user.name}}</div>',
            replace : true,
            compile:function(tElement,tAttrs,transclude){
                // 1.編譯階段...主要可以進行DOM 結構的操作
                //  tElement.append(angular.element('<div>{{user.name}}{{user.count}}</div>'));
                console.log('customTags compile 編譯階段...');
                return {
                    //2.Link 包括 pre 和  post 主要可以用在新增事件的繫結和scope繫結

                    // 2.1.1表示在編譯階段之後,指令連線到子元素之前執行
                    pre:function preLink(scope,iElement,iAttrs,controller){
                        console.log('customTags preLink..')
                    },
                    // 2.1.2表示在所有子元素指令都連線之後才執行
                    post:function postLink(scope,iElement,iAttrs,controller){
                       iElement.on('click',function(){
                           //需要用 $apply觸發一次 髒檢查
                           scope.$apply(function(){
                               scope.user.name = 'click after';
                               scope.user.count = ++i;
                           });
                       })

                        console.log('customTags all child directive link..')
                    }
                }

                // 也可以直接返回 postLink
                // return function postction(scope,iElement,iAttrs,controller){
                //     console.log('compile return fun');
                // }
            },
            // 此link表示的就是 postLink
            // link:function postction(scope,iElement,iAttrs,controller){
            //    iElement.on('click',function(){
            //        scope.$apply(function(){
            //            scope.user.name = 'click after';
            //            scope.user.count = ++i;
            //            // 進行一次 髒檢查
            //        });
            //    })
            // }
        }
      })
【五】controller 、controllerAs 和 require 屬性 
     .directive('bookList', function() {
       return {
        restrict: 'ECAM',
        // controller 會暴露一個API ,利用這個API 可以在多個指令之間通過依賴注入進行通訊
        controller: function($scope) {
            $scope.books = [{
                name: 'php'
            }, {
                name: 'javascript'
            }, {
                name: 'java'
            }];


            this.addBook = function() {


                $scope.$apply(function() {
                    $scope.books.push({
                        name: 'Angularjs'
                    })
                });
            }
        },
        controllerAs: 'bookListController',//controllerAs:給上面的controller 起個別名
        template: '<div><ul><li ng-repeat="book in books">{{book.name}}</li></ul><book-add></book-add></div>',
        replace: true
      }
     })


    .directive('bookAdd', function() {
      return {
        restrict: 'ECAM',
        require: '^bookList',
        //require 可以將其他指令傳遞給自己 ,如此可以去呼叫其他的指令的函式和修改其他指令的欄位,實現不同指令之間的通訊
        // (沒有字首)如果沒有字首,指令將會在自身所提供的控制器中進行查詢,如果沒有找到任何控制器就丟擲一個錯誤。
        // ? 如果在當前指令中沒有找到所需要的控制器,會將null作為傳給link函式的第四個引數。
        // ^ 如果添加了^字首,指令會在上游的指令鏈中查詢require引數所指定的控制器。
        // ?^ 將前面兩個選項的行為組合起來,我們可選擇地載入需要的指令並在父指令鏈中進行查詢。
        template: '<button type="button">新增</button>',
        replace: true,
        link: function(scope, iElement, iAttrs, bookListController) {
            //點選呼叫第一個指令的addBook函式
            iElement.on('click', bookListController.addBook);
        }
      }
    })
【六】 scope 屬性

           scope : 為當前指令建立一個新的作用域
           false : 繼承父元素的作用域
           true : 建立一個新的作用域

          引數:
              &:作用域把父作用域的屬性包裝成一個函式,從而以函式的方式讀寫父作用域的屬性
              =: 作用域的屬性與父作用域的屬性進行雙向繫結,任何一方的修改均會影響到對方
              @:只能讀取父作用域裡的值單項繫結

    .directive('bookList', function () {
        return {
            restrict: 'ECAM',
            controller: function ($scope) {
                $scope.books = $scope.a();
                $scope.books = $scope.b;
                $scope.b.push({name:'nodejs'});
                console.log($scope.c);
            },
            // 建立一個有繼承鏈的獨立作用域
            // scope:true,

            // 當scope 為物件的時獨立的作用域候也會建立一個
            scope:{
                // 將父元素books封裝成一個a函式(&:作用域把父作用域的屬性包裝成一個函式,從而以函式的方式讀寫父作用域的屬性)
                a:'&books'
                // 雙向繫結 b = parentBooks屬性對應的父作用域的表示式(=:作用域的屬性與父作用域的屬性進行雙向繫結,
                //     任何一方的修改均會影響到對方)
                b:'=parentBooks'

                // 只能使用簡單資料型別的方法,不能用物件(@ :只能讀取父作用域裡的值單向繫結)
                c:'@parentTitle'
            },
            controllerAs:'bookListController',
            template: '<div><ul><li ng-repeat="book in books">{{book.name}}</li></ul></div>',
            replace:true
        }
    })


    .controller('firstController', ['$scope', function ($scope) {
        console.log($scope);
        $scope.books = [
            {
                name: 'php'
            },
            {
                name: 'javascript'
            },
            {
                name: 'java'
            }
        ];
        $scope.title = '張三';

    }]);

       注意:html 檔案中的屬性寫法要與指令中定義的相匹配。以上面的為例,html中:

 <div book-list books="books" parent-books="books" parent-title="{{title}}">