Angular學習心得之directive - scope選項與綁定策略
開門見山地說,scope:{}使指令與外界隔離開來,使其模板(template)處于non-inheriting(無繼承)的狀態,當然除非你在其中使用了transclude嵌入,這點之后的筆記會再詳細記錄的。但是這顯然不符合實際開發中的需求,因為實際上,我們經常想要我們的指令能夠在特定的情況下與外界進行數據上的交互,這就需要借助綁定策略之手了。
大家知道,當scope選項寫為scope:{}這種形式的時候,就已經為指令生成了隔離作用域,現在,我們來看看綁定策略的三種形式:& 、= 、@。
首先是@,它將本地作用域和DOM中的屬性值綁定起來(且這個屬性的值必須是父級作用域中的),什么意思呢?說的簡單一點就是假設你在模板中有個雙花括號表達式,然后我們把表達式里的內容和html中指令里特定名字的屬性綁定起來,還是不懂?看看下面的代碼:
JS代碼:
directive("direct",function(){ return{ restrict: 'ECMA', template: '<div>指令中:{{ name }}</div>', scope:{ name:'@forName' } } }) .controller("nameController",function($scope){ $scope.Name="張三"; });
HTML代碼:
<div ng-controller="nameController"> <direct for-name="{{ Name }}"></direct> <div>
運行結果可想而知,{{ name }}成功地與父控制器中的Name綁定起來了。當然這里也可以這樣寫
name:'@' 這樣寫的話,就默認DOM中的屬性名為name了意即 for-name="{{ Name }}"可簡寫為name="{{ Name }}";其實,另外兩個符號=和&也有這樣的簡寫規則,方便起見接下來都使用這種寫法。
@到此為止,接下來就是'='了。=與@的不同點在于,@是針對字符串而用,但=是針對某個對象的引用,
這么說可能不太專業,但就拿上邊的例子而言,我們在html中,把Name這個字符串通過一對雙花括號傳遞給for-name屬性,但如果我們用了=,這里傳入的Name就不應該是一個字符串,而是一個對象的引用。這不是一個很一目了然的概念,所以我用接下來的兩個例子詮釋它的含義。
第一個例子:數組中的對象的引用
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){ $scope.data=[{name:"張三"},{name:"李四"}]; });
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)。這其中的道理跟無參的例子是大同小異的。
大功告成,@,=,&的綁定策略大概就是這樣了。有什么需要補充和糾正的,我懇請各位大神向我提出,謝謝!
來自:http://my.oschina.net/u/2342955/blog/408889