AngularJS 入门2

                                                    AngularJS  入门2

五.使用控制器封装业务逻辑

1. 控制器的作用

我们知道,在AngularJS中,实现数据绑定的核心是scope对象。那么控制器又有什么用呢?

简单地说,没有控制器/controller,我们没有地方定义业务模型

回忆下ng-init指令。我们可以使用ng-init指令在scope对象上定义数据,比如:

   
   
  1. <div ng-init="sb={name:'somebody',gender:'male',age:28}">

但是,ng-init的值是一个AngularJS表达式,没有办法定义方法。

控制器让我们有机会在scope上定义我们的业务逻辑,具体说,可以使用控制器:

   1)  对scope对象进行初始化

   2)  向scope对象添加方法


控制器的一次性

控制器构造函数仅在AngularJS对HTML文档进行编译时被执行一次。从这个角度看, 就更容易理解为何将控制器称为对scope对象的增强:一旦控制器创建完毕,就意味着scope对 象上的业务模型构造完毕,此后就不再需要控制器了- scope对象接管了一切。

控制器对scope的影响

ng-controller指令总是创建一个新的scope对象:


在图中,我们看到:

  1. ng-app指令引发$rootScope对象的创建。开始时,它是一个空对象
  2. body元素对应的scope对象还是$rootScope。ng-init指令将sb对象挂在了$rootScope上。
  3. div元素通过ng-controller指令创建了一个新的scope对象,这个对象的原型是$rootScope。
  4. 因为原型继承的关系,在do函数中对sb的引用指向$rootScope.sb

初始化$scope对象

通常在应用启动时,需要初始化scope对象上的数据模型。我们之前曾使用ng-init指令进行初始化, 而使用控制器则是更为规范的做法。

右边的示例定义了一个ezController,利用这个控制器,我们对业务模型进行了初始化赋值:


请注意,控制器仅仅负责在编译时在scope对象上建立视图对象vm,视图对象和模板的绑定则是由 scope负责管理的。

实例:

javascript:

var ezControllerClass = function($scope){
//view model
$scope.vm = {
sb : {
name : "Jason Stantham",
gender : "male",
age : 48,
career : "actor",
photo : "hiphotos.baidu.com/baike/w%3D268/sign=a03742145bee3d6d22c680cd7b176d41/359b033b5bb5c9eae4c45250d739b6003af3b34a.jpg"
}
};
};
angular.module("ezstuff",[])
.controller("ezController",ezControllerClass);

HTML:

<html ng-app="ezstuff">
<head>
<script src="angular.min.js"></script>
</head>
<body>
<div ng-controller="ezController">
<div>name : {{vm.sb.name}}</div>
<div>gender : {{vm.sb.gender}}</div>
<div>age : {{vm.sb.age}}</div>
<div>career : {{vm.sb.career}}</div>
<div><img ng-src="{{vm.sb.photo}}"></div>
</div>
</body>
</html>


建议:别把任何代码都塞到控制器里!



控制器的设计出发点是封装单个视图的业务逻辑,因此,不要进行以下操作:

  • DOM操作

应当将DOM操作使用指令/directive进行封装。

  • 变换输出形式

应当使用过滤器/filter对输出显示进行转化。

  • 跨控制器共享代码

对于需要复用的基础代码,应当使用服务/service进行封装



六. 使用服务封装可复用的代码

 

1. 创建服务组件


在AngularJS中创建一个服务组件很简单,只需要定义一个具有$get方法的构造函数, 然后使用模块的provider方法进行登记:

  
  
  1. //定义构造函数
  2. var myServiceProvider = function(){
  3. this.$get = function(){
  4. return ....
  5. };
  6. };
  7. //在模块中登记
  8. angular.module"myModule",[])
  9. .provider"myService"myServiceProvider);
右边的示例定义了一个支持四则运算的服务:ezCalculator。你可以点击按钮【3+4=?】 查看效果。   

javascript:

function doCalc(){
var injector = angular.injector(["ezstuff"]),
mycalculator = injector.get("ezCalculator"),
ret = mycalculator.add(3,4);

document.querySelector("#result").textContent = ret;
}

angular.module("ezstuff",[])
.provider("ezCalculator",function(){
this.$get = function(){
return {
add : function(a,b){return a+b;},
subtract : function(a,b){return a-b;},
multiply : function(a,b){return a*b;},
divide: function(a,b){return a/b;}
}
};
})



2.可配置的服务

有时我们希望服务在不同的场景下可以有不同的行为,这意味着服务可以进行配置

比如,我们希望小计算器可以根据不同的本地化区域,给计算结果追加货币符号前缀, 那么需要在这个服务创建之前,首先配置本地化区域的值,然后在具体的计算中, 根据这个值选择合适的货币符号。

AngularJS使用模块的config()方法对服务进行配置,需要将实例化的服务提供者 (而不是服务实例)注入到配置函数中:

  
  
  1. angular.module"myModule",[])
  2. .config(["myServiceProvider"functionmyServiceProvider){
  3. //do some configuration.
  4. }]);

注意:服务提供者provider对象在注入器中的登记名称是:服务名+Provider。 例如: $http的服务提供者实例名称是"$httpProvider"。

右边的示例嵌入了可配置的ezCalculator服务,查看代码体会一下!


javascript实例:

function doCalc(){
var injector = angular.injector(["ezstuff"]),
mycalculator = injector.get("ezCalculator"),
ret = mycalculator.add(3,4);

document.querySelector("#result").textContent = ret;
}

angular.module("ezstuff",[])
.provider("ezCalculator",function(){
var currency = "$";
this.setLocal = function(l){
var repo = {
"CN":"¥",
"US":"$",
"JP":"¥",
"EN":"€"
};
if(repo[l]) currency = repo[l];
};
this.$get = function(){
return {
add : function(a,b){return currency + (a+b);},
subtract : function(a,b){return currency + (a-b);},
multiply : function(a,b){return currency + (a*b);},
divide: function(a,b){return currency + (a/b);}
}
};
})
.config(function(ezCalculatorProvider){
ezCalculatorProvider.setLocal("CN");
});


3. 可配置的服务


有时我们希望服务在不同的场景下可以有不同的行为,这意味着服务可以进行配置

比如,我们希望小计算器可以根据不同的本地化区域,给计算结果追加货币符号前缀, 那么需要在这个服务创建之前,首先配置本地化区域的值,然后在具体的计算中, 根据这个值选择合适的货币符号。

AngularJS使用模块的config()方法对服务进行配置,需要将实例化的服务提供者 (而不是服务实例)注入到配置函数中:

   
   
  1. angular.module"myModule",[])
  2. .config(["myServiceProvider"functionmyServiceProvider){
  3. //do some configuration.
  4. }]);

注意:服务提供者provider对象在注入器中的登记名称是:服务名+Provider。 例如: $http的服务提供者实例名称是"$httpProvider"。

右边的示例嵌入了可配置的ezCalculator服务,查看代码体会一下!


javascript 实例代码:

function doCalc(){
var injector = angular.injector(["ezstuff"]),
mycalculator = injector.get("ezCalculator"),
ret = mycalculator.add(3,4);

document.querySelector("#result").textContent = ret;
}

angular.module("ezstuff",[])
.provider("ezCalculator",function(){
var currency = "$";
this.setLocal = function(l){
var repo = {
"CN":"¥",
"US":"$",
"JP":"¥",
"EN":"€"
};
if(repo[l]) currency = repo[l];
};
this.$get = function(){
return {
add : function(a,b){return currency + (a+b);},
subtract : function(a,b){return currency + (a-b);},
multiply : function(a,b){return currency + (a*b);},
divide: function(a,b){return currency + (a/b);}
}
};
})
.config(function(ezCalculatorProvider){
ezCalculatorProvider.setLocal("US");
});


4. 服务定义语法糖

使用模块provider方法定义服务组件,在有些场景下显得有些笨重。AngularJS友好 地提供了一些简化的定义方法,这些方法通常只是对provider方法的封装, 分别适用于不同的应用场景:

  • factory

使用一个对象工厂函数定义服务,调用该工厂函数将返回服务实例。

  • service

使用一个类构造函数定义服务,通过new操作符将创建服务实例。

  • value

使用一个定义服务,这个值就是服务实例。

  • constant

使用一个常量定义服务,这个常量就是服务实例。


4.1 factory方法

factory方法要求提供一个对象工厂,调用该类工厂将返回服务实例。

   
   
  1. var myServiceFactory = function(){
  2. return ...
  3. };
  4. angular.module"myModule",[])
  5. .factory"myService"myServiceFactory);

INSIDE:AngularJS会将factory方法封装为provider,上面的示例 等同于:

   
   
  1. var myServiceFactory = function(){
  2. return ...
  3. };
  4. angular.module"myModule",[])
  5. .provider"myService"function(){
  6. this.$get = myServiceFactory;
  7. });

右边预置了使用factory方法改写的ezCalculator示例,感受下和provider方法的区别!

javascript 部分代码:
angular.module("ezstuff",[])
.factory("ezCalculator",function(){
return {
add : function(a,b){return a+b;},
subtract : function(a,b){return a-b;},
multiply : function(a,b){return a*b;},
divide: function(a,b){return a/b;}
}
})


4.2 service方法

service方法要求提供一个构造函数,AngularJS使用这个构造函数创建服务实例:

   
   
  1. var myServiceClass = function(){
  2. this.method1 = function(){...}
  3. };
  4. angular.module"myModule",[])
  5. .service"myService"myServiceClass);

INSIDE:AngularJS会将service方法封装为provider,上面的示例 等同于:

   
   
  1. var myServiceClass = function(){
  2. //class definition.
  3. };
  4. angular.module"myModule",[])
  5. .provider"myService"function(){
  6. this.$get = function(){
  7. return new myServiceClass();
  8. };
  9. });

右边预置了使用service方法改写的ezCalculator示例,感受下和factory方法的区别!


Javascrpt 部分代码实例:

var ezCalculatorClass = function(){
this.add = function(a,b){return a+b;};
this.subtract = function(a,b){return a-b;};
this.multiply = function(a,b){return a*b;};
this.divide = function(a,b){return a/b;};
};

angular.module("ezstuff",[]) .service("ezCalculator",ezCalculatorClass);


4.3 value方法


有时我们需要在不同的组件之间共享一个变量,可以将这种情况视为一种服务: provider返回的总是变量的值。

value方法提供了对这种情况的简化封装:

   
   
  1. angular.module"myModule",[])
  2. .value"myValueService""cx129800123");

INSIDE:AngularJS会将value方法封装为provider,上面的示例 等同于:

   
   
  1. angular.module"myModule",[])
  2. .provider"myService"function(){
  3. this.$get = function(){
  4. return "cx129800123";
  5. };
  6. });

javascript 部分实例代码:

var showUserName = function(){
var injector = angular.injector(["ezstuff"]),
username = injector.get("ezUserName");
document.querySelector("#result").textContent = username;
};

angular.module("ezstuff",[])
.value("ezUserName","whoami");


4.4 value方法

有时我们需要在不同的组件之间共享一个常量,可以将这种情况视为一种服务: provider返回的总是常量的值。

constant方法提供了对这种情况的简化封装:

   
   
  1. angular.module"myModule",[])
  2. .constant"myConstantService""Great Wall");

和value方法不同,AngularJS并没有将constant方法封装成一个provider,而仅仅 是在内部登记这个值。这使得常量在AngularJS的启动配置阶段就可以使用(创建任何 服务之前):你可以将常量注入到模块的config()方法中。

在右边的示例中,你可以试着将constant()改成value(),看看还能正常运行吗?


实例代码如下:

function doCalc(){
var injector = angular.injector(["ezstuff"]),
mycalculator = injector.get("ezCalculator"),
ret = mycalculator.add(3,4);

document.querySelector("#result").textContent = ret;
}

angular.module("ezstuff",[])
.constant("ezCurrency","CN")
.provider("ezCalculator",function(){
var currency = "$";
this.setLocal = function(l){
var repo = {
"CN":"¥",
"US":"$",
"JP":"¥",
"EN":"€"
};
if(repo[l]) currency = repo[l];
};
this.$get = function(){
return {
add : function(a,b){return currency + (a+b);},
subtract : function(a,b){return currency + (a-b);},
multiply : function(a,b){return currency + (a*b);},
divide: function(a,b){return currency + (a/b);}
}
};
})
.config(function(ezCurrency,ezCalculatorProvider){
ezCalculatorProvider.setLocal(ezCurrency);
});

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值