AngularJS 指令定義時(shí)的參數(shù)

2018-07-26 17:18 更新

指令定義時(shí)的參數(shù)如下:

  • name
  • priority
  • terminal
  • scope
  • controller
  • require
  • restrict
  • template
  • templateUrl
  • replace
  • transclude
  • compile
  • link

現(xiàn)在我們開始一個(gè)一個(gè)地吃掉它們……,但是并不是按順序講的。

priority
這個(gè)值設(shè)置指令的權(quán)重,默認(rèn)是 0 。當(dāng)一個(gè)節(jié)點(diǎn)中有多個(gè)指令存在時(shí),就按著權(quán)限從大到小的順序依次執(zhí)行它們的 compile 函數(shù)。相同權(quán)重順序不定。
terminal
是否以當(dāng)前指令的權(quán)重為結(jié)束界限。如果這值設(shè)置為 true ,則節(jié)點(diǎn)中權(quán)重小于當(dāng)前指令的其它指令不會(huì)被執(zhí)行。相同權(quán)重的會(huì)執(zhí)行。
restrict
指令可以以哪些方式被使用,可以同時(shí)定義多種方式。
  • E 元素方式 <my-directive></my-directive>
  • A 屬性方式 <div my-directive="exp"> </div>
  • C 類方式 <div class="my-directive: exp;"></div>
  • M 注釋方式 <!-- directive: my-directive exp -->
transclude
前面已經(jīng)講過基本的用法了??梢允?nbsp;'element' 或 true 兩種值。
compile
基本的定義函數(shù)。 function compile(tElement, tAttrs, transclude) { ... }
link
前面介紹過了。大多數(shù)時(shí)候我們不需要單獨(dú)定義它。只有 compile 未定義時(shí) link 才會(huì)被嘗試。 function link(scope, iElement, iAttrs, controller) { ... }
scope
scope 的形式。 false 節(jié)點(diǎn)的 scope , true 繼承創(chuàng)建一個(gè)新的 scope , {} 不繼承創(chuàng)建一個(gè)新的隔離 scope 。 {@attr: '引用節(jié)點(diǎn)屬性', =attr: '把節(jié)點(diǎn)屬性值引用成scope屬性值', &attr: '把節(jié)點(diǎn)屬性值包裝成函數(shù)'}
controller
為指令定義一個(gè) controller , function controller($scope, $element, $attrs, $transclude) { ... }
name
指令的 controller 的名字,方便其它指令引用。
require
要引用的其它指令 conroller 的名字, ?name 忽略不存在的錯(cuò)誤, ^name 在父級(jí)查找。
template
模板內(nèi)容。
templateUrl
從指定地址獲取模板內(nèi)容。
replace
是否使用模板內(nèi)容替換掉整個(gè)節(jié)點(diǎn), true 替換整個(gè)節(jié)點(diǎn), false 替換節(jié)點(diǎn)內(nèi)容。
<a b></a>
var app = angular.module('Demo', [], angular.noop);

app.directive('a', function(){
  var func = function(element, attrs, link){
    console.log('a');
  }

  return {compile: func,
          priority: 1,
          restrict: 'EA'};
});

app.directive('b', function(){
  var func = function(element, attrs, link){
    console.log('b');
  }

  return {compile: func,
          priority: 2,
          //terminal: true,
          restrict: 'A'};
});

上面幾個(gè)參數(shù)值都是比較簡單且容易理想的。

再看 scope 這個(gè)參數(shù):

<div ng-controller="TestCtrl">
  <div a b></div>
</div>
var app = angular.module('Demo', [], angular.noop);

app.directive('a', function(){
  var func = function(element, attrs, link){
    return function(scope){
      console.log(scope);
    }
  }

  return {compile: func,
          scope: true,
          restrict: 'A'};
});

app.directive('b', function(){
  var func = function(element, attrs, link){
    return function(scope){
      console.log(scope);
    }
  }

  return {compile: func,
          restrict: 'A'};
});

app.controller('TestCtrl', function($scope){
  $scope.a = '123';
  console.log($scope);
});

對(duì)于 scope :

  • 默認(rèn)為 false , link 函數(shù)接受的 scope 為節(jié)點(diǎn)所在的 scope 。
  • 為 true 時(shí),則 link 函數(shù)中第一個(gè)參數(shù)(還有 controller 參數(shù)中的 $scope ), scope 是節(jié)點(diǎn)所在的 scope 的 child scope ,并且如果節(jié)點(diǎn)中有多個(gè)指令,則只要其中一個(gè)指令是 true 的設(shè)置,其它所有指令都會(huì)受影響。

這個(gè)參數(shù)還有其它取值。當(dāng)其為 {} 時(shí),則 link 接受一個(gè)完全隔離(isolate)的 scope ,于 true 的區(qū)別就是不會(huì)繼承其它 scope 的屬性。但是這時(shí),這個(gè) scope 的屬性卻可以有很靈活的定義方式:

@attr 引用節(jié)點(diǎn)的屬性。

<div ng-controller="TestCtrl">
  <div a abc="here" xx="{{ a }}" c="ccc"></div>
</div>
var app = angular.module('Demo', [], angular.noop);

app.directive('a', function(){
  var func = function(element, attrs, link){
    return function(scope){
      console.log(scope);
    }
  }

  return {compile: func,
          scope: {a: '@abc', b: '@xx', c: '@'},
          restrict: 'A'};
});

app.controller('TestCtrl', function($scope){
  $scope.a = '123';
});
  • @abc 引用 div 節(jié)點(diǎn)的 abc 屬性。
  • @xx 引用 div 節(jié)點(diǎn)的 xx 屬性,而 xx 屬性又是一個(gè)變量綁定,于是 scope 中 b 屬性值就和 TestCtrl 的 a 變量綁定在一起了。
  • @ 沒有寫 attr name ,則默認(rèn)取自己的值,這里是取 div 的 c 屬性。

=attr 相似,只是它把節(jié)點(diǎn)的屬性值當(dāng)成節(jié)點(diǎn) scope 的屬性名來使用,作用相當(dāng)于上面例子中的 @xx :

<div ng-controller="TestCtrl">
  <div a abc="here"></div>
</div>
var app = angular.module('Demo', [], angular.noop);

app.directive('a', function(){
  var func = function(element, attrs, link){
    return function(scope){
      console.log(scope);
    }
  }

  return {compile: func,
          scope: {a: '=abc'},
          restrict: 'A'};
});

app.controller('TestCtrl', function($scope){
  $scope.here = '123';
});

&attr 是包裝一個(gè)函數(shù)出來,這個(gè)函數(shù)以節(jié)點(diǎn)所在的 scope 為上下文。來看一個(gè)很爽的例子:

<div ng-controller="TestCtrl">
  <div a abc="here = here + 1" ng-click="show(here)">這里</div>
  <div>{{ here }}</div>
</div>
var app = angular.module('Demo', [], angular.noop);

app.directive('a', function(){
  var func = function(element, attrs, link){
    return function llink(scope){
      console.log(scope);
      scope.a();
      scope.b();

      scope.show = function(here){
        console.log('Inner, ' + here);
        scope.a({here: 5});
      }
    }
  }

  return {compile: func,
          scope: {a: '&abc', b: '&ngClick'},
          restrict: 'A'};
});

app.controller('TestCtrl', function($scope){
  $scope.here = 123;
  console.log($scope);

  $scope.show = function(here){
    console.log(here);
  }
});

scope.a 是 &abc ,即:

scope.a = function(){here = here + 1}

只是其中的 here 是 TestCtrl 的。

scope.b 是 &ngClick ,即:

scope.b = function(){show(here)}

這里的 show() 和 here 都是 TestCtrl 的,于是上面的代碼最開始會(huì)在終端輸出一個(gè) 124 。

當(dāng)點(diǎn)擊“這里”時(shí),這時(shí)執(zhí)行的 show(here) 就是 llink 中定義的那個(gè)函數(shù)了,與 TestCtrl 無關(guān)。但是,其間的 scope.a({here:5}) ,因?yàn)?nbsp;a 執(zhí)行時(shí)是 TestCtrl 的上下文,于是向 a 傳遞的一個(gè)對(duì)象,里面的所有屬性 TestCtrl 就全收下了,接著執(zhí)行 here=here+1 ,于是我們會(huì)在屏幕上看到 6 。

這里是一個(gè)上下文交錯(cuò)的環(huán)境,通過 & 這種機(jī)制,讓指令的 scope 與節(jié)點(diǎn)的 scope 發(fā)生了互動(dòng)。真是鬼斧神工的設(shè)計(jì)。而實(shí)現(xiàn)它,只用了幾行代碼:

case '&': {
  parentGet = $parse(attrs[attrName]);
  scope[scopeName] = function(locals) {
    return parentGet(parentScope, locals);
  }
  break;
}

再看 controller 這個(gè)參數(shù)。這個(gè)參數(shù)的作用是提供一個(gè) controller 的構(gòu)造函數(shù),它會(huì)在 compile 函數(shù)之后, link 函數(shù)之前被執(zhí)行。

<a>haha</a>
var app = angular.module('Demo', [], angular.noop);

app.directive('a', function(){
  var func = function(){
    console.log('compile');
    return function(){
      console.log('link');
    }
  }

  var controller = function($scope, $element, $attrs, $transclude){
    console.log('controller');
    console.log($scope);

    var node = $transclude(function(clone_element, scope){
      console.log(clone_element);
      console.log('--');
      console.log(scope);
    });
    console.log(node);
  }

  return {compile: func,
          controller: controller,
          transclude: true,
          restrict: 'E'}
});

controller 的最后一個(gè)參數(shù), $transclude ,是一個(gè)只接受 cloneAttachFn 作為參數(shù)的一個(gè)函數(shù)。

按官方的說法,這個(gè)機(jī)制的設(shè)計(jì)目的是為了讓各個(gè)指令之間可以互相通信。參考普通節(jié)點(diǎn)的處理方式,這里也是處理指令 scope 的合適位置。

<a b>kk</a>
var app = angular.module('Demo', [], angular.noop);

app.directive('a', function(){
  var func = function(){
  }

  var controller = function($scope, $element, $attrs, $transclude){
    console.log('a');
    this.a = 'xx';
  }

  return {compile: func,
          name: 'not_a',
          controller: controller,
          restrict: 'E'}
});

app.directive('b', function(){
  var func = function(){
    return function($scope, $element, $attrs, $controller){
      console.log($controller);
    }
  }

  var controller = function($scope, $element, $attrs, $transclude){
    console.log('b');
  }

  return {compile: func,
          controller: controller,
          require: 'not_a',
          restrict: 'EA'}
});

name 參數(shù)在這里可以用以為 controller 重起一個(gè)名字,以方便在 require 參數(shù)中引用。

require 參數(shù)可以帶兩種前綴(可以同時(shí)使用):

  • ? ,如果指定的 controller 不存在,則忽略錯(cuò)誤。即:require: '?not_b' 如果名為 not_b 的 controller 不存在時(shí),不會(huì)直接拋出錯(cuò)誤, link 函數(shù)中對(duì)應(yīng)的 $controller 為 undefined 。
  • ^ ,同時(shí)在父級(jí)節(jié)點(diǎn)中尋找指定的 controller ,把上面的例子小改一下:<a><b>kk</b></a> 把 a 的 require 改成(否則就找不到 not_a 這個(gè) controller ):require: '?^not_a'

還剩下幾個(gè)模板參數(shù):

template 模板內(nèi)容,這個(gè)內(nèi)容會(huì)根據(jù) replace 參數(shù)的設(shè)置替換節(jié)點(diǎn)或只替換節(jié)點(diǎn)內(nèi)容。
templateUrl 模板內(nèi)容,獲取方式是異步請(qǐng)求。
replace 設(shè)置如何處理模板內(nèi)容。為 true 時(shí)為替換掉指令節(jié)點(diǎn),否則只替換到節(jié)點(diǎn)內(nèi)容。
<div ng-controller="TestCtrl">
  <h1 a>原始內(nèi)容</h1>
</div>
var app = angular.module('Demo', [], angular.noop);

app.directive('a', function(){
  var func = function(){
  }

  return {compile: func,
          template: '<p>標(biāo)題 {{ name }} <button ng-click="name=\'hahaha\'">修改</button></p>',
          //replace: true,
          //controller: function($scope){$scope.name = 'xxx'},
          //scope: {},
          scope: true ,
          controller: function($scope){console.log($scope)},
          restrict: 'A'}
});

app.controller('TestCtrl', function($scope){
  $scope.name = '123';
  console.log($scope);
});

template 中可以包括變量引用的表達(dá)式,其 scope 遵尋 scope 參數(shù)的作用(可能受繼承關(guān)系影響)。

templateUrl 是異步請(qǐng)求模板內(nèi)容,并且是獲取到內(nèi)容之后才開始執(zhí)行指令的 compile 函數(shù)。

最后說一個(gè) compile 這個(gè)參數(shù)。它除了可以返回一個(gè)函數(shù)用為 link 函數(shù)之外,還可以返回一個(gè)對(duì)象,這個(gè)對(duì)象能包括兩個(gè)成員,一個(gè) pre ,一個(gè) post 。實(shí)際上, link 函數(shù)是由兩部分組成,所謂的 preLink 和 postLink 。區(qū)別在于執(zhí)行順序,特別是在指令層級(jí)嵌套的結(jié)構(gòu)之下, postLink 是在所有的子級(jí)指令 link 完成之后才最后執(zhí)行的。 compile 如果只返回一個(gè)函數(shù),則這個(gè)函數(shù)被作為 postLink 使用:

<a><b></b></a>
var app = angular.module('Demo', [], angular.noop);

app.directive('a', function(){
  var func = function(){
    console.log('a compile');
    return {
      pre: function(){console.log('a link pre')},
      post: function(){console.log('a link post')},
    }
  }

  return {compile: func,
          restrict: 'E'}
});

app.directive('b', function(){
  var func = function(){
    console.log('b compile');
    return {
      pre: function(){console.log('b link pre')},
      post: function(){console.log('b link post')},
    }
  }

  return {compile: func,
          restrict: 'E'}
});
以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)