天天看点

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.在数组中声明的依赖参数必须与容器中的组件的名字对应

继续阅读