Angular指令

Angular指令概述

指令是一種執(zhí)行的信號(hào),一旦發(fā)布了這個(gè)指令,就要執(zhí)行某項(xiàng)動(dòng)作,HTML中的標(biāo)簽都可以理解為指令,但Angular中的指令要復(fù)雜很多,不但要?jiǎng)?chuàng)建元素,還要給元素附加某些特定的行為,因此,Angular中的指令是一個(gè)在特定DOM元素上執(zhí)行的函數(shù)

指令定義的基礎(chǔ)

在Angular中,定義指令需要調(diào)用directive方法,該方法接收兩個(gè)參數(shù):

var app = angular.module('myapp', []);
app.directive(name, fn);

在定義的模塊上使用directive方法創(chuàng)建一個(gè)指令,name為指令的名稱,fn是一個(gè)函數(shù),它將返回一個(gè)對(duì)象,在這個(gè)對(duì)象中,定義了這個(gè)指令的全部行為

<div>
  <ts-hello></ts-hello>
  <div ts-hello></div>
  <div class="ts-hello"></div>
  <div data-ts-hello></div>
</div>
<script>
  var app = angular.module('myapp', []);
  app.directive('tsHello', function () {
    return {
      restrict: 'EAC',
      template: '<h3>Hello, Angular!</h3>'
    }
  })
</script>

設(shè)置指令對(duì)象的基礎(chǔ)屬性

replace:它的屬性值是布爾類型,當(dāng)該屬性值為true時(shí),表示用模板中的內(nèi)容替換指令標(biāo)記,否則則不替換,直接顯示指令標(biāo)記,默認(rèn)為false

templateUrl:它的屬性值是一個(gè)URL地址,該地址指向一個(gè)模板頁面

<div>
  <ts-tplfile></ts-tplfile>
  <ts-tplscript></ts-tplscript>
  <ts-tplcache></ts-tplcache>
</div>
<script>
  var app = angular.module('myapp', []);

  app.run(function ($templateCache) {
    $templateCache.put('cache', '<h3>模板內(nèi)容來源于緩存</h3>')
  });

  app.directive('tsTplfile', function () {
    return {
      restrict: 'EAC',
      templateUrl: 'tpl.html'
    };
  });

  app.directive('tsTplscript', function () {
    return {
      restrict: 'EAC',
      templateUrl: 'tpl',
      replace: true
    }
  });

  app.directive('tsTplcache', function () {
    return {
      restrict: 'EAC',
      templateUrl: 'cache'
    }
  });
</script>

Angular指令對(duì)象的重要屬性

指令對(duì)象中的transclude屬性

transclude屬性的值是布爾值,默認(rèn)為false,表示不開啟,如果設(shè)置為true,則開啟該屬性,當(dāng)開啟后,則可以在模板中通過ng-transclude方式替換指令元素中的內(nèi)容

<ts-hello>
  <div>我是自定義指令在HTML里的內(nèi)容</div>
</ts-hello>
<script>
  var app = angular.module('MyApp', []);
  app.directive('tsHello', function () {
    return {
      restrict: 'EA',
      template: '<div ng-transclude></div>',
      replace: true,
      transclude: true
    }
  });
</script>

指令對(duì)象中的link屬性

指令對(duì)象中的link屬性的值是一個(gè)函數(shù),在該函數(shù)中可以操控DOM元素對(duì)象,包括綁定元素的各類事件,定義事件觸發(fā)時(shí)執(zhí)行的內(nèi)容

link: function(scope, element, attrs) {
  // ...
}

link函數(shù)包含3個(gè)主要的參數(shù):

  • scope參數(shù)表示指令所在的作用域
  • element參數(shù)表示指令中的元素,改元素可以通過Angular內(nèi)部封裝的jqLite框架進(jìn)行調(diào)用
  • attrs參數(shù)表示指令元素的屬性集合通過這個(gè)參數(shù)可以獲取元素中的各類屬性
<script type="text/ng-template" id="tpl">
  <button>點(diǎn)擊按鈕</button>
</script>

<div>
  <ts-tplscipt></ts-tplscipt>
  <div>{{content}}</div>
</div>
<script>
  var app = angular.module('myapp', []);
  app.directive('tsTplscipt', function () {
    return {
      restrict: 'EAC',
      templateUrl: 'tpl',
      replace: true,
      link: function (scope, element, attrs) {
        element.bind('click', function () {
          scope.$apply(function () {
            scope.content = '這是點(diǎn)擊后顯示的內(nèi)容';
          })
          attrs.$$element[0].disabled = true;
        })
      }
    }
  });
</script>

指令對(duì)象中的compile屬性

該屬性比起link屬性使用的很少,該屬性返回一個(gè)函數(shù)或?qū)ο蟆.?dāng)返回一個(gè)函數(shù)時(shí),該函數(shù)名稱為post,而返回一個(gè)對(duì)象時(shí),該對(duì)象中則包含兩個(gè)名為prepost方法函數(shù),這兩個(gè)函數(shù)名是系統(tǒng)提供的,不可修改。

<div ng-controller="myctrl">
  <ts-a>
    <ts-b>
      {{tip}}
    </ts-b>
  </ts-a>
</div>
<script>
  var app = angular.module('myapp', []);
  app.controller('myctrl', function ($scope) {
    $scope.tip = '跟蹤compile執(zhí)行過程';
  });

  app.directive('tsA', function () {
    return {
      restrict: 'EAC',
      compile: function (tEle, tAttrs, trans) {
        console.log('正在編譯A指令');
        return {
          pre: function (scope, element, attrs) {
            console.log('正在執(zhí)行A指令中的pre函數(shù)');
          },
          post: function (scope, element, attr) {
            console.log('正在執(zhí)行A指令中的post函數(shù)');
          }
        }
      }
    }
  });

  app.directive('tsB', function () {
    return {
      restrict: 'EAC',
      compile: function (tEle, tAttrs, trans) {
        console.log('正在編譯B指令');
        return {
          pre: function (scope, element, attrs) {
            console.log('正在執(zhí)行B指令中pre函數(shù)');
          },
          post: function (scope, element, attrs) {
            console.log('正在執(zhí)行B指令中的post函數(shù)');
          }
        }
      }
    }
  });
</script>

Angular指令對(duì)象的scope屬性

在Angular指令對(duì)象中,scope屬性使用頻率很高,它的值包含兩種類型,一種是布爾值,另一類是JSON對(duì)象

scope屬性是布爾值

使用scope屬性自定義指令時(shí),默認(rèn)是布爾類型,初始值為false。在這種情況下,指令中的作用域就是指令元素所在的作用域。我們將指令中的作用域稱為子作用域,把指令元素所在作用域稱為父作用域,當(dāng)scopefalse時(shí),子作用域和父作用域完全相同,一方變化,則另一方也會(huì)自動(dòng)發(fā)生變化

當(dāng)scopetrue時(shí),則表示子作用域是獨(dú)立創(chuàng)建的,父作用域中內(nèi)容的改變會(huì)影響子作用域,但子作用域的內(nèi)容發(fā)生變化,并不會(huì)修改父作用域中的內(nèi)容

<script type="text/ng-template" id="tpl">
  <div>{{message}}</div>
  <button ng-transclude></button>
</script>

<div>
  <input type="text" ng-model="message" placeholder="請(qǐng)輸入提示內(nèi)容">
  <ts-message>固定</ts-message>
</div>
<script>
  var app = angular.module('myapp', []);
  app.directive('tsMessage', function () {
    return {
      restrict: 'EAC',
      templateUrl: 'tpl',
      transclude: true,
      scope: true,
      link: function (scope, element, attrs) {
        element.bind('click', function () {
          scope.$apply(function () {
            scope.message = '這是單擊后的值';
          })
        })
      }
    }
  })
</script>

第二個(gè)例子:

html:

<div ng-controller="myCtrl">
  父親: {{name}}
  <input ng-model="name">
  <div my-directive></div>
</div>
var app = angular.module('myApp', [])
  app.controller('myCtrl', ['$scope', function ($scope) {
    $scope.name = 'leifeng';
  }]);
  app.directive('myDirective', function () {
    return {
      restrict: 'EA',
      scope: true,  //父作用域發(fā)生改變,子作用域會(huì)變化,子作用域的變化不會(huì)影響父作用域
      template: '<div>兒子: {{name}}<input ng-model="name"></div>'
    }
  });

scope屬性是對(duì)象

除了將scope屬性設(shè)置為布爾值之外,還可以設(shè)置成一個(gè)JSON對(duì)象,如果是對(duì)象,那么父作用域與子作用域是完全獨(dú)立的,不存在任何關(guān)聯(lián)

app.directive('myDirective', function () {
  return {
    resrict: 'EA',
    scope: {},  //父作用域與子作用域相互不影響,改變?nèi)我庖环蕉疾粫?huì)改變另一方
    template: //....
  }
})

這時(shí),子作用域中如果需要添加屬性,則可以通過link函數(shù),在scope上添加,如果子作用域需要與調(diào)用父作用域的屬性和方法,則需要在這個(gè)JSON對(duì)象中添加綁定策略

在JSON對(duì)象中添加的有3種綁定策略,分別是@=&

(1) @綁定

如果父作用域的屬性內(nèi)容修改了,子作用域?qū)?yīng)的屬性內(nèi)容也會(huì)隨之修改,而如果子作用域?qū)傩詢?nèi)容修改了,是不會(huì)影響父作用域?qū)?yīng)的屬性內(nèi)容的。

html:

<div ng-controller="myCtrl">
  父親: {{name}}
  <input ng-model="name">
  <my-directive name="{{name}}"></my-directive>
</div>

javascript:

<script>
  var app = angular.module('myApp', [])
  app.controller('myCtrl', ['$scope', function ($scope) {

  }]);
  app.directive('myDirective', function () {
    return {
      restrict: 'EA',
      scope: {
        name: '@'  //指令作用域中變量與父作用域中一致,直接使用@綁定
      },
      replace: true,
      template: '<div>兒子: {{name}}<input ng-model="name"></div>'
    }
  });
</script>

(2) =綁定

=綁定的功能是創(chuàng)建一個(gè)父作用域與子作用域可以同時(shí)共享的屬性,即父作用域修改了該屬性,子作用域也隨之改變,反之亦然。

html:

<div ng-controller="myCtrl">
  <input type="text" ng-model="color" placeholder="Enter a color">
  {{color}}
  <hello-world color='color'></hello-world>
   <!--注意上面自定義指令里屬性的寫法-->
</div>

javascript:

<script>
  var app = angular.module('myApp', []);
  app.controller('myCtrl', ['$scope', function ($scope) {}]);
  app.directive('helloWorld', function () {
    return {
      restrict: 'EA',
      replace: true,
      scope: {
        color: '='
      },
      template: '<div style="background-color:{{color}}">Hello World<input type="text" ng-model="color"></div>'
    }
  });
</script>

(3) &綁定

&綁定的功能可以在獨(dú)立的子作用域中直接調(diào)用父作用域的方法,在調(diào)用時(shí)可以向函數(shù)傳遞參數(shù)。

<div ng-controller="myCtrl">
  <input type="text" ng-model="name" placeholder="Eneter a color">
  {{name}}
  <hello-world saysomething999="say();" name="kaindy"></hello-world>
</div>

javascript:

<script>
  var app = angular.module('myApp', []);

  app.controller('myCtrl', ['$scope', function ($scope) {
    $scope.say = function () {
      alert('hello');
    }
    $scope.name = 'leifeng';
  }]);

  app.directive('helloWorld', function () {
    return {
      restrict: 'EA',
      replace: true,
      scope: {
        saysomething: '&saysomething999',
        name: '@'
      },
      template: '<button type="button" ng-bind="name" ng-init="saysomething();"></button>'
    }
  });
</script>

Angular指令對(duì)象的require和controller屬性

requirecontroller兩個(gè)屬性常用于多個(gè)自定義指令元素嵌套時(shí),即當(dāng)一個(gè)子元素指令需要與父元素指令通信時(shí),就需要使用這兩個(gè)屬性

require和controller屬性的概念

require屬性在創(chuàng)建子元素指令時(shí)添加,它的屬性值用于描述與父元素指令通信時(shí)的方式,如^符號(hào)表示向外層尋找指定名稱的指令,?符號(hào)表示即使沒有找到,也不會(huì)出現(xiàn)異常

require: "^?myDirective"

controller屬性值是一個(gè)構(gòu)造函數(shù),在創(chuàng)建父元素指令時(shí)添加,并可以在函數(shù)中創(chuàng)建多個(gè)屬性或方法。在添加后,這些屬性和方法都會(huì)被實(shí)例的對(duì)象所繼承,而這個(gè)實(shí)例對(duì)象則是子元素指令中link函數(shù)的第4個(gè)參數(shù)

也就是說,當(dāng)在子元素指令中添加了require屬性,并通過屬性值指定父元素指令的名稱,那么就可以通過子元素指令中link函數(shù)的第4個(gè)參數(shù)來訪問父元素指令中controller屬性添加的方法。

controller: function () {
  this.a = function (childDirective) {
    // 方法a的函數(shù)體
  }
}
  • controller的屬性值對(duì)應(yīng)一個(gè)構(gòu)造函數(shù)
  • this代表父元素指令本身
  • a表示構(gòu)造函數(shù)中的一個(gè)任意的方法
  • childDirective形參表示子元素指令中的scope對(duì)象

html:

<div>
  <!--父元素指令-->
  <ts-parent>
    <div>{{ptip}}</div>
    <!--子元素指令-->
    <ts-child>
      <div>{{ctip}}</div>
    </ts-child>
    <button ng-click="click()">換位</button>
  </ts-parent>
</div>

javascript:

<script>
  var app = angular.module('myApp', []);

  app.directive('tsParent', function () {
    return {
      restrict: 'EA',
      controller: function ($scope, $compile, $http) {
        this.addChild = function (c) {
          $scope.ptip = '今天天氣不錯(cuò)!';
          $scope.click = function () {
            $scope.tmp = $scope.ptip;
            $scope.ptip = c.ctip;
            c.ctip = $scope.tmp;
          }
        }
      }
    }
  });

  app.directive('tsChild', function () {
    return {
      restrict: 'EA',
      // 與父元素指令tsParent進(jìn)行通信
      require: '^?tsParent',
      // 第4個(gè)參數(shù)表示父元素指令本身,可以調(diào)用定義在其上的方法
      link: function (scope, element, attrs, ctrl) {
        scope.ctip = '氣溫正好18攝氏度';
        ctrl.addChild(scope);
      }
    }
  });
</script>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容