前面通過視頻學習了解了指令的概念,這里學習一下指令中的作用域的相關內容。
通過獨立作用域的不同綁定,可以實現更具適應性的自定義標簽。借由不同的綁定規則綁定屬性,從而定義出符合更多應用場景的標簽。
本篇將會總結下面的內容:
1 為何需要獨立作用域
2 如何實現獨立作用域
3 作用域的數據綁定
之前有一些錯誤,是由於replace拼寫錯誤導致的。
拼寫正確后,網友發現報錯,無法正常工作。這是因為模板中存在單標簽<br>,導致模板無法正確解析~
再次感謝博友們提出的錯誤!
獨立作用域的作用
為了便於理解,先看一下下面這個例子:
<!doctype html> <html ng-app="myApp"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <script src="http://apps.bdimg.com/libs/angular.js/1.2.16/angular.min.js"></script> </head> <body> <div ng-controller="MainController"> <xingoo></xingoo> <xingoo></xingoo> <xingoo></xingoo> </div> <script type="text/javascript"> var myAppModule = angular.module("myApp",[]); myAppModule .controller('MainController', function($scope){ }) .directive("xingoo",function(){ return { restrict:'AE', template:'<div><input type="text" ng-model="username"/>{{username}}</div><br>' }; }); </script> </body> </html>
可以看到,在script中,創建了一個指令,該指令實現了一個自定義的標簽。
標簽<xingoo></xingoo>的作用是 替換成 一個輸入框和一個數據顯示。
這樣就會出現下面的效果:
分析:
當我們自己創建某個指令時,這個指令肯定不可能只使用一次,是要重復多次使用的,有的在一個頁面內或者一個控制器內需要使用多次。
類似上面的這種場景,在任何一個輸入框內改變數據,都會導致其他的標簽內的數據一同發生改變,這顯然不是我們想要的。
這個時候就需要獨立作用域了。
如何實現獨立作用域
下面看看獨立作用域的效果:
<!doctype html> <html ng-app="myApp"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <script src="http://apps.bdimg.com/libs/angular.js/1.2.16/angular.min.js"></script> </head> <body> <div ng-controller="MainController"> <xingoo></xingoo> <xingoo></xingoo> <xingoo></xingoo> </div> <script type="text/javascript"> var myAppModule = angular.module("myApp",[]); myAppModule .controller('MainController', function($scope){ }) .directive("xingoo",function(){ return { restrict:'AE', scope:{},//scope=true, template:'<div><input type="text" ng-model="username"/>{{username}}</div><br>' }; }); </script> </body> </html>
只需要在定義指令時,添加scope:{}這個屬性,就可以使標簽擁有自己的作用域。
僅僅是添加這一行代碼而已,就實現了獨立作用域。
在進行輸入時,每個模板內使用自己的數據,不會相互干擾。
作用域數據綁定
自定義標簽或者進行擴展時,會有這樣的需求場景,要在標簽中添加一些屬性,實現一些復雜功能。
關於這些屬性,獨立作用域是如何的做的呢?看看下面的內容吧。
舉個例子:
<xingoo say="name"></xingoo> <xingoo say="name()"></xingoo>
假設傳入的是上面這種,我們如何區分它傳入的到底是變量呢?還是字符串呢?還是方法呢?
因此AngularJS有了三種自定義的作用域綁定方式:
1 基於字符串的綁定:使用@操作符,雙引號內的內容當做字符串進行綁定。
2 基於變量的綁定:使用=操作符,綁定的內容是個變量。
3 基於方法的綁定:使用&操作符,綁定的內容時個方法。
基於字符串的綁定@:
<!doctype html> <html ng-app="myApp"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <script src="http://apps.bdimg.com/libs/angular.js/1.2.16/angular.min.js"></script> </head> <body> <div ng-controller="MainController"> <xingoo say="test string"></xingoo> <xingoo say="{{str2}}"></xingoo> <xingoo say="test()"></xingoo> </div> <script type="text/javascript"> var myAppModule = angular.module("myApp",[]); myAppModule .controller('MainController', function($scope){ $scope.str1 = "hello"; $scope.str2 = "world"; $scope.str3 = "angular"; }) .directive("xingoo",function(){ return { scope:{ say:'@' }, restrict:'AE', template:"<div>{{say}}</div>", replace:true }; }); </script> </body> </html>
看一下代碼,在body中使用了三次自定義的標簽,每種標簽的內部有一個say的屬性,這個屬性綁定了一個雙引號的字符串。
在指令的定義中,添加了scope:{say:'@'}這個鍵值對屬性,也就是說,angular會識別say所綁定的東西是一個字符串。
在模板中,使用表達式{{say}}輸出say所表示的內容。
可以看到,雙引號內的內容都被當做了字符串。當然{{str2}}表達式會被解析成對應的內容,再當做字符串。
基於變量的綁定=:
<!doctype html> <html ng-app="myApp"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <script src="http://apps.bdimg.com/libs/angular.js/1.2.16/angular.min.js"></script> </head> <body> <div ng-controller="myAppCtrl"> ctrl:<input type="text" ng-model="testname"><br> directive:<xingoo name="testname"></xingoo> </div> <script type="text/javascript"> var myAppModule = angular.module("myApp",[]); myAppModule.controller("myAppCtrl",['$scope',function($scope){ $scope.testname="my name is xingoo"; }]); myAppModule.directive("xingoo",function(){ return { restrict:'AE', scope:{ name:'=' }, template:'<input type="text" ng-model="name">', repalce:true } }) </script> </body> </html>
在上面的代碼中,可以看到
1 在控制器myAppCtrl對應的div中,定義了一個變量ng-model —— testname。
2 testname對應的是輸入框中輸入的值。
3 然后把這個變量當做一個參數傳遞給xingoo這個標簽的name屬性。
4 在xingoo標簽中,又把這個name綁定到模板中的一個輸入框內。
最終兩個輸入框的內容被連接起來,無論改變哪一個輸入框內的值,testname與name都會發生改變。
通過下面這張圖可以看出來:
在指令中通過scope指定say綁定規則是變量的綁定方式。
最終通過xingoo標簽內的屬性依賴關系把 testname與name連接在一起:
基於方法的綁定&:
上面展示了基於字符串和變量的綁定方法,下面看看基於方法的綁定:
<!doctype html> <html ng-app="myApp"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <script src="http://apps.bdimg.com/libs/angular.js/1.2.16/angular.min.js"></script> </head> <body> <div ng-controller="myAppCtrl"> <xingoo say="sayHello(name)"></xingoo> <xingoo say="sayNo(name)"></xingoo> <xingoo say="sayYes(name)"></xingoo> </div> <script type="text/javascript"> var myAppModule = angular.module("myApp",[]); myAppModule.controller("myAppCtrl",['$scope',function($scope){ $scope.sayHello = function(name){ console.log("hello !"+ name); }; $scope.sayNo = function(name){ console.log("no !"+ name); }; $scope.sayYes = function(name){ console.log("yes !"+ name); }; }]); myAppModule.directive("xingoo",function(){ return { restrict:'AE', scope:{ say:'&' }, template:'<input type="text" ng-model="username"/><br>'+ '<button ng-click="say({name:username})">click</button><br>', repalce:true } }) </script> </body> </html>
這段代碼中scope中的綁定規則變成了&,也就是方法綁定。
在body中,通過自定義標簽傳入了三個方法,分別是sayHello(name),sayNo(name),sayYes(name),這三個方法都需要一個name變量。
在指令的定義中,模板替換成一個輸入框,一個按鈕:
輸入框:用於輸入username,也就是三個方法需要的參數name。
按鈕:點擊觸發函數——通過綁定規則,綁定到相應的方法。
也就是說
通過say在scope中的定義,angular知道了say對應的是個方法;
通過{name:username}的關聯,知道了傳入的是username。
從而交給對應的方法執行。
頁面效果:
參考
[1] 大漠窮求,AngularJS實戰:http://www.imooc.com/video/3085/0