AngularJS笔记-继承机制

继承模式

AngularJS中没有提供内建的用于继承的特性,在本文中,我们将一起来学习如何在AngularJS组件中使用普通的JavaScript继承模式。

皓眸大前端开发学习

转载请注明出处:http://www.haomou.net/2014/09/12/2014_angularjs_2/

控制器继承

首先,我们来谈谈控制器。实际上控制器不太可能从父控制器中进行继承。这是因为子控制器的作用域将会原型继承父控制器的作用域。因此当你需要重用来自父控制器中的功能时,你所要做的就是在父作用域中添加相应的方法。这样一来,子控制器将会通过它的作用域的原型来获取父作用域中的所有方法。例如:

1
2
3
4
5
6
7
8
9
myModule.controller('ParentCtrl',function($scope){
$scope.parentMethod = function(){
//...
};
});

myModule.controller('ChildCtrl',function($scope){
$scope.parentMethod();//这样就可以运行
});

当然,这样的继承方式创造了非常强的耦合但是仅仅是单方向的耦合,因此你不能从你的父控制器中调用子控制器中的方法。对于这种情况,你需要使用事件分发:

1
2
3
4
5
6
7
8
9
10
11
12
13
myModule.controller('ParentCtrl',function($scope){
$scope.$broadcast('event',args);
$scope.$on('event-response',function (result){
});
});

myModule.controller('ChildCtrl',function($scope){
$scope.$on('event',function (args){
var result;
//...
$scope.$emit('event-response',result);
});
});

上面的代码仅作为参考使用,如果你需要从父控制器中调用子控制器的方法,那么需要了解Angular中的controller间的通信机制。

Angularjs为在scope中为我们提供了冒泡和隧道机制,\$broadcast会把事件广播给所有子controller,而\$emit则会将事件冒泡传递给父controller,\$on则是angularjs的事件注册函数,有了这一些我们就能很快的以angularjs的方式去解决angularjs controller之间的通信,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<div ng-app="app" ng-controller="parentCtr">
<div ng-controller="childCtr1">name :
<input ng-model="name" type="text" ng-change="change(name);" />
</div>
<div ng-controller="childCtr2">Ctr1 name:
<input ng-model="ctr1Name" />7 </div>
</div>

angular.module("app", []).controller("parentCtr",
function ($scope) {
$scope.$on("Ctr1NameChange",

function (event, msg) {
console.log("parent", msg);
$scope.$broadcast("Ctr1NameChangeFromParrent", msg);
});
}).controller("childCtr1", function ($scope) {
$scope.change = function (name) {
console.log("childCtr1", name);
$scope.$emit("Ctr1NameChange", name);
};
}).controller("childCtr2", function ($scope) {
$scope.$on("Ctr1NameChangeFromParrent",

function (event, msg) {
console.log("childCtr2", msg);
$scope.ctr1Name = msg;
});
});

这里childCtr1的name改变会以冒泡传递给父controller,而父controller会对事件包装在广播给所有子controller,而childCtr2则注册了change事件,并改变自己。注意父controller在广播时候一定要改变事件name。

假设现在你有两个页面,它们的大部分功能都相同,其中完全相同的功能超过50%。两个页面的视图完全不同但是可能视图后面的逻辑非常相似。在这种情形中你可以创建一个基本的控制器来封装基本的逻辑,然后再创建两个子控制器来继承它。基本控制器并不需要作为一个AngularJS控制器组件来实现,你完全可以将它创建为一个构造器函数:

1
2
3
4
5
6
7
8
9
10
11
12
function BaseCtrl($scope,$location,...){
$scope.commonScopeMethod = function(){
//...
};
$scope.commonVar = 42;
}
BaseCtrl.prototype.commonMethod1 = function(){
//...
};
BaseCtrl.prototype.commonMethod2 = function(){
//...
};

现在子控制器可以轻松地从基本控制器中继承方法和属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
function ChildCtrl($scope,$location,...){
BaseCtrl.call(this,$scope,$location,...);
$scope.childScopeMethod = function(){
};
}

ChildCtrl1.prototype = Object.create(BaseCtrl.prototype);

ChildCtrl1.prototype.chidMethod1 = function(){
this.commonMethod1();
};

myModule.controller('ChildCtrl1',ChildCtrl1);

在这里我们使用了经典的继承模式。我们也可以使用同同样的方法来创造第二个子控制器。

Service继承

正如你所了解的我们有两种方式来创建可注入(通过依赖注入)的AngularJS service:

1
2
3
module.factory(name,factoryFn)
module.service(name,factoryFn)
module.factory

在module.factory中factoryFn返回一个对象字面量,它是真正的service。幕后ANgularJS会在injector内部调用factory函数。

如果我们需要在由module.factory实例化的services之间进行继承,由Object.create进行的原型继承就合适。

我们先来创建基本service:

1
2
3
4
5
6
7
8
9
10
11
var BaseService = (function(){
var privateVar = 0;
return {
someAwesomeStuff: function(){
if(privateVar === 42){
alert('You reached the answer!');
}
privateVar += 1;
};
};
})();

现在这里有一个子service:

1
2
3
4
5
6
7
8
var ChildService = Object.create(BaseService);   
ChildService.someMoreAwesomeStuff = function(){
//...
};

module.factory('ChildService',function(){
return ChildService;
});

现在你可以在不同的组件中注入ChildService,并重用继承自BaseService的方法。

1
2
3
4
function MyCtrl(ChildService){
ChildService.someAwesomeStuff();
}
moudle.service

既然我们有了factory为什么还需要service呢?假设我是一个迷糊的开发者,我并不理解原型继承的真正威力但是我想对我的模型使用经典的样式。通过使用它我们就可以创建一系列构造器函数来很好的控制我们的模型。

下面是一个我们对module.service使用原型继承模式的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function Human(name){
this.name = name;
}
Human.prototype.talk = function(){
return 'My name is ' + this.name;
}
Human.$inject = ['name'];

function Superhero = function(name abilities){
Human.call(this,name);
this.abilities = abilities;
}

Superhero.prototype = Object.create(Human.prototype);
Superhero.prototype.saveTheWorld = function(){
return 'Saving the world with ' + this.abilities.join(', ');
};
Super.$inject = ['name','AbilitiesCollection'];

angular.module('demo').service('Human',Human);
angular.module('demo').service('Superhero',Superhero);
angular.module('demo').value('name','Super Dev');
angular.module('demo').value('AbilitiesCollection',['C++','JavaScript']);

谢谢!

转载请注明出处:http://www.haomou.net/2014/09/12/2014_angularjs_2/

有问题请留言。T_T 皓眸大前端开发学习 T_T