開門見山地說,scope:{}使指令與外界隔離開來,使其模板(template)處於non-inheriting(無繼承)的狀態,固然除非你在其中使用了transclude嵌入,這點以後的筆記會再詳細記錄的。可是這顯然不符合實際開發中的需求,由於實際上,咱們常常想要咱們的指令可以在特定的狀況下與外界進行數據上的交互,這就須要藉助綁定策略之手了。html
你們知道,當scope選項寫爲scope:{}這種形式的時候,就已經爲指令生成了隔離做用域,如今,咱們來看看綁定策略的三種形式:& 、= 、@。express
首先是@,它將本地做用域和DOM中的屬性值綁定起來(且這個屬性的值必須是父級做用域中的),什麼意思呢?說的簡單一點就是假設你在模板中有個雙花括號表達式,而後咱們把表達式裏的內容和html中指令裏特定名字的屬性綁定起來,仍是不懂?看看下面的代碼:數組
JS代碼:函數
directive("direct",function(){ return{ restrict: 'ECMA', template: '<div>指令中:{{ name }}</div>', scope:{ name:'@forName' } } }) .controller("nameController",function($scope){ $scope.Name="張三"; });
HTML代碼:spa
<div ng-controller="nameController"> <direct for-name="{{ Name }}"></direct> <div>
運行結果可想而知,{{ name }}成功地與父控制器中的Name綁定起來了。固然這裏也能夠這樣寫雙向綁定
name:'@' 這樣寫的話,就默認DOM中的屬性名爲name了意即 for-name="{{ Name }}"可簡寫爲name="{{ Name }}";其實,另外兩個符號=和&也有這樣的簡寫規則,方便起見接下來都使用這種寫法。rest
@到此爲止,接下來就是'='了。=與@的不一樣點在於,@是針對字符串(準確來講是表達式expression)而用,但=是針對某個對象的引用,code
這麼說可能不太專業,但就拿上邊的例子而言,咱們在html中,把Name這個字符串經過一對雙花括號傳遞給for-name屬性,但若是咱們用了=,這裏傳入的Name就不該該是一個字符串,而是一個對象的引用。這不是一個很一目瞭然的概念,因此我用接下來的兩個例子詮釋它的含義。htm
第一個例子:數組中的對象的引用對象
JS代碼:
directive("direct",function(){ return{ restrict: 'ECMA', template: '<div>指令中:{{ case.name }}</div>', scope:{ case:'=' } } }) .controller("nameController",function($scope){ $scope.data=[{name:"張三"},{name:"李四"}]; });
HTML代碼:
<div ng-controller="nameController"> <direct case="data[0]"></direct> <direct case="data[1]"></direct> <div>
結果就是,一個張三,一個李四。這個例子中,data是一個對象數組,裏面包含了兩個對象,因此,咱們分別把兩個對象傳遞給了case這個屬性,case屬性就把這個對象的引用傳遞給了模板中咱們寫的{{ case.name }}中的case;而若是你在=後邊加上了本身定義的名字,那隻要把html裏case屬性換成那個名字就能夠了。
第二個例子:經典的雙向輸入框
按照Angular的入門案例,建立兩個雙向綁定的輸入框,最簡單的實現方式就是:
<input ng-model="test"/> <input ng-model="test"/>
使用ng-model指令就能夠作到了。接着,咱們在本身的指令中實現這個效果。
JS代碼:
directive("direct",function(){ return{ restrict: 'ECMA', template: '<div>指令中:<input ng-model="model"/></div>', scope:{ model:'=' } } }) .controller("nameController",function($scope){ });
HTML代碼:
<div ng-controller="nameController"> 父級scope中:<input ng-model="mark"/> <direct model="mark"/></direct> </div>
這就完成了,其實只不過是加了一點小把戲,把ng-model換成了model而已。
注意到,這兩個例子中,都是使用對象的引用,而不是單純的字符串,這也是=能夠進行雙向綁定的關鍵。
最後是&符號。它的含義是:對父級做用域進行綁定,並將其中的屬性包裝成一個函數,注意,是屬性,意即,任何類型的屬性都會被包裝成一個函數,好比一個單純的字符串,或是一個對象數組,或是一個函數方法,若是是字符串、對象數組和無參的函數,那麼可想而知,它們都會被包裝成一個無參的函數,如果有參的函數方法則反之,而且咱們須要爲其傳入一個對象。如今,分別針對有參和無參兩種狀況舉例。
無參狀況↓
JS代碼:
.directive("direct",function(){ return{ restrict: 'ECMA', template: '<div>{{ title }}</div>'+'<div><ul><li ng-repeat="x in contents">{{ x.text }}< /li></ul></div>', scope:{ getTitle:'&', getContent:'&' }, controller:function($scope){ $scope.title=$scope.getTitle(); //調用無參函數 $scope.contents=$scope.getContent(); //調用無參函數 } } }) .controller("nameController",function($scope){ $scope.title="標題"; $scope.contents =[{text:1234},{text:5678}]; });
HTML代碼:
<div ng-controller="nameController"> <direct get-title="title" get-content="contents"></direct> </div>
這個例子有幾個注意點:
1.指令的本地屬性(即模板裏花括號中的屬性)須要從本地取值,因此使用了controller選項,而在controller選項中,兩個無參方法分別返回了父級scope中的title字符串和contents對象數組。
2.在HTML中,咱們把設置了get-title和get-content的屬性值爲title和contents,這實際上就完成了與父級scope的綁定,由於咱們才能夠從那兒取得實質的內容。
OK,有參狀況↓
JS代碼:
.directive("direct",function(){ return{ restrict: 'ECMA', template: '<div><input ng-model="model"/></div>'+'<div><button ng-click="show({name:model})">show</button>', scope:{ show:'&' } } }) .controller("nameController",function($scope){ $scope.showName=function(name){ alert(name); } });
HTML代碼:
<div ng-controller="nameController"> <direct show="showName(name)"></direct> </div>
這個例子中,經過模板中的ng-click觸發了show函數並將一個叫作model的對象做爲name參數傳遞了進去,而在html中,咱們把show的屬性值設爲showName(name)。這其中的道理跟無參的例子是大同小異的。
總結:
爲何Angular要爲咱們提供這樣一套綁定策略呢?就是由於它想讓咱們在爲指令建立隔離做用域的同時,還能訪問到父級中的屬性,這就像,你在隔離做用域身上打了一個洞,而後用一條管道,把指令內部和外界的屬性給連起來(綁定),而且一切的通訊都只能經過這條管道來實行。這是我目前能作到的最深入的理解了,可能還有須要的補充和糾正的地方,但願你們能抽空指點我一下,感激涕零!