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
相关文章推荐
- (七)理解angular中的module和injector,即依赖注入
- AngularJS $injector 依赖注入
- (七)理解angular中的module和injector,即依赖注入
- 理解angular中的module和injector,即依赖注入
- 探究Angular依赖注入对象$injector
- 理解angular中的module和injector,即依赖注入
- Angular 理解module和injector,即依赖注入
- Angular 4依赖注入学习教程之组件服务注入(二)
- (七)理解angular中的module和injector,即依赖注入
- 理解angular中的module和injector,即依赖注入
- 用原生js简单模仿angular的依赖注入
- AngularJS $injector 依赖注入详解
- Angular 理解module和injector,即依赖注入
- iOS - 创建依赖组件的pickerView
- Angular:依赖注入
- Angular 2中的依赖注入
- Angularjs MVC 以及 $scope 作用域 Angularjs 模块 的 run 方法 以及依赖注入中代码压缩问题
- 深入理解Angular依赖注入
- 用spring的注解建立bean与bean之间的关系组件装配及自动注入依赖对象
- Angular2 中的依赖注入