如今前端框架出現的愈來愈多,幾年前的angularjs已近處於被淘汰的地步了。可是angularjs有幾樣東西是頗有借鑑價值的,不管之後的ECMAScript的標準如何發展,這幾樣東西都是咱們須要掌握的技巧。例如:依賴注入和指令
javascript
依賴注入在java中大量使用,或者說是java出名的開源框架都會用到。java是經過JVM的解釋器特性,將class在內存中解析爲<class>的數據結構,經過反射來實現依賴注入。咱們只須要註冊依賴名稱、依賴類關係、獲取依賴類就能夠很方便的使用。而javascript也有JVM解釋器的相似實現,或者說javascript的解釋器更加符合一個動態語言的工做方式,更加方便的使用依賴注入功能。
html
咱們正常使用:代碼耦合過高
前端
function animal(name){ this.name=name; } animal.prototype.eat = function(food){ console.log(" I am a "+this.name+" , I'am eating "+food); } function keep(){ this.animal=new animal("老虎"); this.feed=function(food){ this.animal.eat(food); } } //使用 var keep1=new keep(); keep1.feed("肉");
外部注入:java
function keeper(animal){ this.animal=animal; } keeper.prototype.feed = function(food){ this.animal.eat(food); } //外部注入 var pig=new animal("pig"); var keeper1=new keeper(pig); keeper1.feed("青菜"); var keeper2=new keeper(pig); keeper1.feed("土豆");
angularjs裏面的的依賴注入:從下面的moduleInstance裏面看出,模塊的服務都放在$provide裏面
angularjs
每個模塊的結構: var moduleInstance = { // Private state _invokeQueue: invokeQueue, //執行隊列 _configBlocks: configBlocks,//配置塊 _runBlocks: runBlocks, //運行塊 requires: requires, //須要的依賴 name: name, //名稱 provider: invokeLater('$provide', 'provider'), factory: invokeLater('$provide', 'factory'), service: invokeLater('$provide', 'service'), value: invokeLater('$provide', 'value'), constant: invokeLater('$provide', 'constant', 'unshift'), animation: invokeLater('$animateProvider', 'register'), filter: invokeLater('$filterProvider', 'register'), controller: invokeLater('$controllerProvider', 'register'), directive: invokeLater('$compileProvider', 'directive'), config: config, run: function(block) { runBlocks.push(block); return this; } };
angularjs的$provider和$injector:數組
一、其中$provider是$injector內部的一個對象,用來存放咱們創造的服務。也能夠經過上面的moduleInstance看出,每個咱們建立的module都會有$injector來存放$provide,而後$provide來存放咱們建立的服務。瀏覽器
providerCache = { $provide: { provider: supportObject(provider), factory: supportObject(factory), service: supportObject(service), value: supportObject(value), constant: supportObject(constant), decorator: decorator } } 函數 function provider(name, provider_) { assertNotHasOwnProperty(name, 'service'); if (isFunction(provider_) || isArray(provider_)) { provider_ = providerInjector.instantiate(provider_); } if (!provider_.$get) { throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name); } return providerCache[name + providerSuffix] = provider_; } 使用方式: $provide.provider('test',function(){ this.name="test"; this.$get=function(){ return name;//閉包 } }); app.controller('myCtrl',function($scope,test){ $scope.test=test; });
二、$injector是一個注入器,也能夠說是用來查詢服務的工具類。也是每一個module都有一個$injector(包括angularjs自己)用來存放$provide,而$provide則使咱們真正的用來存放service的對象。
前端框架
angular.module('myModule2',[]). factory('myService',function(){ return { test:function(text){ console.log('test the injectors:'+text); } } }); //獲取myModule2的injector var injector = angular.injector(['myModule2']); //獲取myService裏面的函數 var test=injector.get('myService'); //使用 test.test("hello injector");
指令是Angularjs應用裏面重要的一部分。經過HTML的組合製做一個HTML元素以及綁定在元素上的angularjs的服務。
數據結構
a、元素建立(DOM的特性):
閉包
restrict:使用限制 ( E:元素:看成元素使用 A:單作attribute使用 C:看成class使用 M:單作註解使用 ) templateUrl/template:模版,利用HTML組裝 replace:是否替換換掉HTML顯示,在瀏覽器的ELEMENT裏面顯示新元素 priority:指令的優先級,當多個指令執行的時候,用來執行complie函數裏面的方法的先後順序。
b、對外的scope:(子類和父類通訊橋樑,要想在指令中使用MVVM的功能,必須執行scope類型)
scope是angularjs操做的核心,這裏的scope是指指令裏面的scope和父類的scope的聯繫 { flase:共享父類的做用域、子類/父類修改一個都改動 true:繼承父類的做用域,可是新建獨立做用域。在指令初始化的時候使用父類的值,以後子類修改不會改變父類的值 {}:新建一個做用域,單獨做用。在使用scope:{}時候,能夠經過屬性擴展來解決,父類的做用域和指令scope做用域通訊。由於不是全部的數據都須要通訊,這就須要區別對待。 scope:{ myName : '=', //綁定到父類scope的myName上(屬性雙向綁定) mySexy : '=mySexyAttr', //綁定到父類scope的mySexyAttr上(屬性雙向綁定) myAge : '@', //綁定到父類scope的myAge 上(屬性單向綁定,子類變父類不變,傳值用{{}}) myAge1 : '@myAgeAttr' //綁定到父類scope的myAgeAttr 上(屬性單向綁定,子類變父類不變,傳值用{{}}) onSay : '&' //綁定到父類onSay 的方法上(方法綁定) onSay1 : '&onSayFunc' //綁定到父類onSayFunc 的方法上(方法綁定) } }
c、對外參數require:指令之間的通訊橋樑
一、若是須要組合指令的時候使用 require:指令或者指令數組 用法1、 require : '^?test' 用法二 require : ['^?test1','test2'] ?:尋找指令名稱,若是沒找到則報錯 ^:在指令尋找方法名,並向父類查找。若是沒有^,則只在該指令中查找
d:行爲參數:指令綁定的服務
一、controller:先於link執行的方法,還能夠經過require傳遞給其它的指令使用。(通常不用) controller:function($scope,$element,$attrs){ $scope:做用域 $element:對應的元素 $attrs:元素上的屬性 $transclude: } 二、link:後於controller執行的函數,和不一樣的controller區別不大。(優先使用) link:function(scope,elem,attrs,ctrl){ scope:做用域 elem:對應的元素 attrs:元素上的屬性 ctrl:從require上傳遞過來的指令數組 } 三、bug避免在使用自定義的時候,若是字符串有大小寫,要加如- myApp.directive('circleUtils', function(){ return { restrict : 'E', replace : false, transclude: true, scope : { outerStyle : '@outerStyle', inlineStyle : '@inlineStyle', degree : '@degree' } 使用 <circle-utils outer-Style="{{outerStyle}}" degree="{{degree}}" inline-Style="{{inlineStyle}}"></circle-utils>
案例()
<!DOCTYPE html> <html ng-app="myModule"> <head> <script src="angular.js"></script> </head> <body ng-controller='myController'> <div> <div style="background-color:blue">圈圖</div> <hr> <div ng-style="outerStyle"> <div ng-style="inlineStyle" align="center">{{degree*100}}%</div> </div> <hr/> <div > <circle-utils outer-Style="{{outerStyle}}" degree="{{degree}}" inline-Style="{{inlineStyle}}"></circle-utils> </div> </div> </body> <script > var myApp = angular.module('myModule',[]); myApp.controller('myController',function($scope){ $scope.degree=0.8; $scope.width=80; $scope.outerStyle={ "width":""+$scope.width+"px", "background-color":"red", "height":"20px" }; $scope.inlineStyle={ "width":""+($scope.degree*$scope.width)+"px", "background-color":"blue", "height":"20px" }; }); myApp.directive('circleUtils', function(){ return { restrict : 'E', replace : false, transclude: true, scope : { outerStyle : '@outerStyle', inlineStyle : '@inlineStyle', degree : '@degree' }, template : '<div ng-style="{{outerStyle}}"><div ng-style="{{inlineStyle}}" align="center">{{degree*100}}%</div></div>', link : function(scope ,elem ,attrs ,ctrl){ console.log(scope.outerStyle); console.log(scope.inlineStyle); } } }); </script> </html>
效果