天天看點

AngularJS(九)

今天繼續學自定義服務

使用provider()方法建立自定義服務

這個方式相較其他方法的優點在于開發者可以在建立angular.Module的配置選項中對服務對象進行配置

注意:建立自定義服務的時候必須為該注冊函數的this定義一個$get函數,該函數的傳回值就是自定義服務的對象。

<body ng-app="app">
		<div ng-controller="ctrl">
			使用者名:<input type="text" name="user.name" ng-model="name" /><br>
			{{reversedName}}<br>
			name:{{serviceName}}<br>
			age:{{serviceAge}}<br>
		</div>
		<script>
			var app=angular.module('app',[],function($fkServiceProvider){
				$fkServiceProvider.setName("yeeku");
			});
			app.provider('$fkService',function(){
				let name;
				this.setName = function(newName){
					name = newName;
				}
				let age;
				this.$get = function(){
					return {
						name:name,
						setAge:function(newAge){
							age = newAge;
						},
						getAge:function(){
							return age;
						},
						reverse:function(str){
							str = str +'' ;
							let result = '' ;
							for(let i = str.length-1;i>=0;i--){
								result +=str.charAt(i);
							}
							return result;
						}
					}
				}
			});
			app.controller('ctrl',function($scope,$fkService){
				$scope.serviceName = $fkService.name;
				$fkService.age = 29;
				$scope.serviceAge = $fkService.age;
				$scope.$watch("name",function(newVal,oldVal,scope){
					$scope.reversedName = $fkService.reverse(newVal);
				});
			});
			
		</script>
	</body>
           

在過濾器中使用自定義服務

如果需要在過濾器中使用自定義服務,隻要在注冊過濾器函數時***聲明自定義服務作為參數***即可

<body ng-app="app" >
		<div ng-controller="ctrl" >
			使用者名:<input type="text" name="user.name" ng-model="name" /><br>
			{{name|reverse}}<br>
			
		</div>
		<script>
			var app=angular.module('app',[]);
			app.factory('$fkService',function(){
				let service = {};
				service.reverse = function(str){
					str = str+ '' ;
					let result = '' ;
					for(let i = str.length-1;i>=0;i--){
						result +=str.charAt(i);
					}
					return result;
				}
				return service;
			});
			
			app.filter('reverse',function($fkService){
				return function(x){
					return $fkService.reverse(x);
				};
			});
			app.controller('ctrl',angular.noop);
		</script>
	</body>
           

然後最終學完服務了,服務其實我算是學的一知半解,後面還是要回顧一遍的

開始學習依賴注入

這個和spring的有點像,但是我spring隻在學校選修課粗略的學過,是以接下來的學習可能會有點困難

依賴注入的作用很顯然,就是為了避免各元件的寫死耦合。

他有四個主要的組成部分:

容器:容器負責管理一切元件

注冊元件:隻有先向容器注冊元件之後,容器才能管理他們,并管理他們的依賴。angular.Module對象和$provide分别提供了5個方法用于注冊元件

擷取元件:通過容器擷取被管理的元件,ng使用$injector擷取容器的元件

聲明依賴:聲明元件之間的依賴管理,容器根據聲明完成注入

對于AngularJS來說,他的子產品就充當了容器的角色,他的子產品包括了控制器、服務、過濾器、指令。

<body ng-app="app">
		<div></div>
		<script>
			var app1 = angular.module('app',[]);
			
			var app2 = angular.module('app');
			console.log(app1 ==app2);
		</script>
	</body>
           

該程式第一行是建立了子產品,第二行是擷取了子產品

每次建立子產品的同時也建立了DI容器

建立後注冊的兩種方式前面已經講了,module和provide,還有前面注冊自定義服務的三種方法也可以用來注冊元件,此外還有以下三種:

constant(name,obj):注冊一個常量對象,該對象可以被provider和service通路

value(name,obj):注冊一個變量對象,該對象隻能被service()方法通路,不能被provider()通路

decorator(name,decorFn):注冊一個裝飾器函數,該裝飾器函數可用于修改或代替其他服務的實作

****前兩個方法如果第二個參數obj傳入函數,相當于注冊了自定義服務

angular.Module和$provide提供的注冊方法都是一樣的,每個子產品在建立或配置階段都可以由系統自動注入一個$provide服務,這個服務是ng自動提供的,他們兩個的唯一差別就是$provide是在ng子產品的配置階段傳入的,是以用于配置階段的注冊元件,angular.Module是建立階段

使用$injector對象獲得元件

前面說了分為四個部分,擷取元件就是其中的第三個部分

為了擷取容器中元件提供了$injector對象,該對象既可以通過angular.injector()方法來擷取,也可以通過在控制器、過濾器、服務的注冊函數中聲明形參來擷取。

在調用該方法時必須傳入要加載的子產品的參數,一定要加載ng系統子產品才行

擷取對象後,對象提供了以下幾種方法:

has(name):判斷是否包含名為name的元件

get(name):根據元件名來擷取元件

invoke(fn):以依賴注入為被調用函數fn傳入參數,進而執行fn

<body ng-app="app">
		<div ng-controller="ctrl">
			
		</div>
		<script>
			var app=angular.module("app",[]);
			app.value("user",{name:"ddd",age:29});   //注冊
			app.controller('ctrl',function($injector){
				console.log($injector.has("user"));
				console.log($injector.get("user").name);
				console.log($injector.get("user").age);
			});
			var injector = angular.injector(['ng','app']); //調用injector建立注入器
			
			console.log("user.name:"+injector.get('user').age);
			console.log("user.age:"+injector.get('user').age);
			
			injector.invoke(function(user){
				console.log(user.name+",你好");
			});
		</script>
	</body>
           

首先這個控制器ctrl聲明了名為$injector的形參

然後新建立了一個變量injector作為注入器使用了injector的方法

然後用“注入器名.get“擷取了元件内容

也可以使用injector對象調用指定函數invoke,injector對象會自動為該函數依賴注入參數

angular.injector也可以調用多次

<body ng-app="app" >
		<div ng-controller="ctrl">
			
		</div>
		<script>
			let app = angular.module("app",[])
			.value("user",{name:"yeeku",age:29})
			.controller("ctrl",angular.noop);
			
			let injector1 = angular.injector(['ng',"app"]);
			
			let injector2 = angular.injector(['ng',"app"]);
			
			console.log(injector1 == injector2);
			console.log(injector1.get("user").name);
			console.log(injector2.get("user").name);
		</script>
	</body>
           

有上述結果可以知道,雖然他們建立的注入器都是同個對象,輸出内容也一樣,但是本質上不是同一個對象

總結4個主要的組成部分:

容器:ng的子產品就是容器,程式建立AngularJS子產品的時候同時建立容器

注冊容器:module和provide分别提供的5個方法

擷取元件:使用了$injector擷取,其中has()判斷是否存在指定元件,get()方法用于獲得指定元件

聲明依賴:ng一共提供了3種聲明依賴的方式

隐式依賴注入

前面的都算隐式,就是讓ng自動掃描函數所需要的形參名,ng會根據形參名從容器中查找對應的元件作為函數的參數,是以隻需要保證參數名稱的正确性,不需要考慮參數的順序

這種方式較為簡單,但是如果釋出項目的時候js代碼被壓縮了,則函數的形參名可能會發生改變,導緻注入方式錯誤。

是以,實際開發過程中應該盡量少用這種方式。為了避免在開發中不小心使用了隐式依賴注入的方式,開發者可以為ng子產品增加ng-strict-di指令-将該指令添加到指定了ng-app的元素上,如此隐式就禁用了

行内數組式依賴注入

在這種方式下,所有被依賴的參數都需要以相同的順序存放在一個數組裡面,數組的值與後面接受依賴注入的函數的參數要一一對應,并同時保證以下兩點:

1.在數組中聲明的依賴參數的順序必須與接受依賴注入的函數的參數的順序保持一緻

2.在數組中聲明的依賴參數必須與容器中的元件的名字對應

繼續閱讀