您的位置:首页 > Web前端 > AngularJS

Angular之依赖注入(injector)与原生View组件

2016-10-15 17:58 417 查看

依赖注入

1. 依赖注入原理

每一个Angular应用都有一个injector注入器来处理依赖的创建,注入器实际上是一个负责查找和创建依赖的服务定位器,所以声明的依赖注入对象都是由它来进行处理。

此外,当获取injector注入器对象后,还可以调用对象的get函数来获得任何一个已经被定义过的服务的实例。

app.controller('myController',['$scope',function($scope){
...
}]);


app.config(function($controllerProvider){
$controllerProvider.register('myController',['$scope',function($scope){
...
}]);
}) ;


  以上两段代码执行后的功能是相同的,不过第一段代码在angular中执行的本质是第二段代码。

  当用户在创建一个控制器是,实际上是在
config
函数中调用
controllerProvider
服务的
register
方法,完成一个控制器的创建,然后再调用
injector
注入器完成各个依赖对象的注入。

<div ng-controller="myController">
<div>{{text}}</div>
<button ng-click="onClick(1)">早上</button>
<button ng-click="onClick(2)">上午</button>
<button ng-click="onClick(3)">下午</button>
<button ng-click="onClick(4)">晚上</button>
</div>
<script type="text/j
4000
avascript">
var app=angular.module('myapp',[]);
app.config(function($provide){
$provide.provider('show_1',function(){
this.$get=function(){
return{
val:function(name){
return name;
}
}
}
})
});
app.config(function($provide){
$provide.factory('show_2',function(){
return{
val:function(name){
return name;
}
}
})
});
app.config(function($provide){
$provide.value('show_3',function(name){
return name;
})
});
app.config(function($provide){
$provide.service('show_4',function(){
return{
val:function(name){
return name;
}
}
})
});

app.controller('myController',['$scope','show_1','show_2','show_3','show_4',
function($scope,show_1,show_2,show_3,show_4){
$scope.onClick=function(t){
switch(t){
case 1:
$scope.text=show_1.val('早上好!');
break;
case 2:
$scope.text=show_2.val('上午好!');
break;
case 3:
$scope.text=show_3('下午好!');
break;
case 4:
$scope.text=show_4.val('晚上好!');
break;
}
}
}])
</script>


  以上代码,先通过
$provide
服务中的
provider()  factory()  value()  service
方法分别在模块中定义名称为
show_1  show_2  show_3  show_4
的可注入型变量,而这些变量又分别对应一个函数,这些函数功能相同,都是返回字符内容。

2. 依赖注入标记

推断式注入

标记式注入

行内注入

2.1 推断式注入

  推断式注入是一种猜测式的注入,在没有明确的声明的情况下,angular会认定参数名称就是依赖注入的函数名,并在内部调用函数函数对象的
toString()
方法,获取对应的参数列表,最后调用注入器将这些参数注入应用的实例中,从而实现依赖注入的过程。

<div ng-controller="myController">
<input type="button" value="alert" ng-click="onClick('I\'m a alert')" />
</div>
<script type="text/javascript">
var app=angular.module('myapp',[])
app.factory('$show',function($window){
return{
show:function(text){
$window.alert(text)
}
}
});
app.controller('myController',function($scope,$show){
$scope.onClick=function(msg){
$show.show(msg)
}
})
</script>


  以上代码,在创建控制器的时候,并没有使用
[]
或者进行标志性的声明,因此注入器通过参数的名称
$scope,$show
来推断依赖服务与控制器的关系。

  这种注入方式不需要关注参数的顺序,因为Angular会自动处理,但是使用这种注入方式,意味着代码不能被压缩或者混淆,否则将可能导致Angular无法正确推断,出现错误

2.2 标识式注入

调用
$inject
属性来完成。

<div ng-controller="myController">
<div class="show">{{text}}</div>
<input type="button" value="alert" ng-click='onShow("I\"m a alert.")' />
<input type="button" value="write" ng-click='onWrite("Today is cold!")' />
</div>
<script type="text/javascript">
var app=angular.module('myapp',[]);
var myController=function($scope,$show,$write){
$scope.onShow=function(msg){
$show.show(msg);
}
$scope.onWrite=function(msg){
$scope.text=$write.write(msg);
}
};
myController.$inject=['$scope','$show','$write'];

app.controller('myController', myController);
app.factory('$show', ['$window', function($window){
return {
show:function(text){
$window.alert(text);
}
};
}]);
app.factory('$write', function(){
return {
write:function(text){
return text;
}
};
})

</script>


  以上代码中,
myController
控制器通过调用
$inject
属性,向函数中注入了3个名称为
$scope  $show $write
的服务,注意这里的注入顺序必须与构造时的一样,否则将报错。

2.3 行内注入

  无论是推断式还是标识式注入声明,都显得有些冗余,为此行内注入应运而生。

行内注入也是推荐的一种注入方法

<div ng-controller="myController">
<div class="show">{{text}}</div>
<input type="button" value="Sum" ng-click='onClick(5,10)' />
</div>
<script type="text/javascript">
var app=angular.module('myapp',[]);
app.factory('$sum', function(){
return{
add:function(m,n){
return m+n;
}
}
});

app.controller('myController', ['$scope','$sum', function($scope,$sum){
$scope.onClick=function(m,n){
$scope.text=$sum.add(m,n);
}
}])

</script>


3. $injector常用API

3.1 has和get方法

has

功能:根据传入的名称,从注册的列表中查找对应的服务,如果找到返回true,否则返回fasle

调用格式:injector.has(name)

get

功能:返回指定名称的服务实例,获取到服务的实例对象后,就可以直接调用服务中的属性和方法。

调用格式:injector.get(name)

<div ng-controller="myController">
<div class="show">{{text}}</div>
<input type="button" value="Sum" ng-click='onClick(5,10)' />
</div>
<script type="text/javascript">
var app=angular.module('myapp',[]);
app.factory('$custom',function(){
return {
print:function(msg){
console.log(msg);
}
};
});
//如果创建多个模块,则可在数组中添加多个
var injector=angular.injector(['myapp']);
var has=injector.has('$custom');
console.log(has);

if(has){
var custom=injector.get('$custom');
custom.print('得到$custom实例');
}
app.controller('myController', ['$scope','$custom',function($scope,$custom){
//...
}])
</script>


3.2 invoke方法

  
invoke
是一个功能比较强大的方法,它最为常用的场景就是执行一个自定义的函数,除此之外,在执行函数时,还能传递变量给函数自身,调用格式如下:

injector.invoke(fn,[self],[locals])


  其中,
injector
为获取的
$injector
对象,参数
fn
为需要执行的函数名称,可选参数
self
是一个对象,表示用于函数中的
this
变量,可选参数
locals
也是一个对象,它能为函数中的变量名传递提供方法支持。

<div ng-controller="myController"></div>
<script type="text/javascript">
var app=angular.module('myapp',[]);
app.factory('$custom',function(){
return {
print:function(msg){
console.log(msg);
}
};
});
var injector=angular.injector(['myapp']);
var fn=function($custom){
$custom.print('函数执行成功!');
}
injector.invoke(fn);
app.controller('myController', ['$scope','$custom',function($scope,$custom){
//...
}])
</script>


  其中
fn()
是一个自定义方法,为了能够调用这个自定义方法,需要调用
$injector
invoke()
方法,该方法不仅能执行对应的函数,而且还能返回被执行函数返回的值。

4. 依赖注入的应用场景

构建控制器时

调用工厂方法构造模块时

4.1 构建控制器

  控制器是一个应用的行为集合,主要负责应用的各项动作和逻辑处理,因此,它长长需要注入各类服务,用于各类逻辑的调用,常用的控制器代码如下:

//标识式注入方式
var myController=function($scope,dep1,dep2,...){
//控制器中的处理代码
}
myController.$inject=['$scope','dep1','dep2',...];

//行内注入方式,建议使用这一种方式
angular.module('myapp',[])
.controller('myController',['$scope','dep1','dep2',...,
function($scope,dep1,dep2,...){
//控制器中的处理代码
}]);


4.2 调用工厂方法

  所谓的工厂方法,指得是类似于
config  factory  directive  filter
等构造性质的方法:

angular.module('myapp',[])
.config(['dep1','dep2',...function(dep1,dep2,...){...}])
.factory('serviceName',['dep1','dep2',...function(dep1,dep2,...){...}])
.dirctive('directiveName',['dep1','dep2',...,
function(dep1,dep2,...){...}])
.filter('filterName',['dep1','dep2',...,
function(dep1,dep2,...){...}])


Angular中的MVC模式

1. Model

例如:

$scope.students=[
{name:'zhangsan',gender:'female'},
{name:'lisi',gender:'male'},
{name:'wangwu',gender:'male'},
]


2. Controller

3. View组件

  Angular应用大部分情况下是单页应用程序,因此为了在视图模板中实现多个功能,需要在页面的局部进行刷新或切换,想要实现这一效果,需要在视图模板中借助
ng-view
指令,在控制器中引入
$routeProvider
服务。

注意,这里除了引入
angular.min.js
之外,还需要引入
angular-route.min.js
文件。

<div>
<a href="#/">首页</a> |
<a href="#/book">图书</a> |
<a href="#/game">游戏</a> |
</div>
<div ng-view></div>
<script type="text/javascript">
var app=angular.module('myapp',['ngRoute']);
app.controller('myController_1', ['$scope',function($scope){
$scope.title='这是首页';
}]);
app.controller('myController_2', ['$scope',function($scope){
$scope.title='这是图书页';
}]);
app.controller('myController_3', ['$scope',function($scope){
$scope.title='这是游戏页';
}]);
app.config(['$routeProvider',function($routeProvider){
$routeProvider
.when('/',{
controller:'myController_1',
template:'<div>{{title}}</div>'
})
.when('/book',{
controller:'myController_2',
template:'<div>{{title}}</div>'
})
.when('/game',{
controller:'myController_3',
template:'<div>{{title}}</div>'
})
.otherwise({
redirectTo:'/'
});
}])
</script>


  因为原生route组件存在比较多的限制,所以建议使用
angular-ui-router
,相比于原生,后者支持嵌套视图多视图

关于’angular-ui-router’详细跳转到github
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: