Angular入门教程四

时间:2022-07-04 19:29:13

4.8依赖注入DI

通过依赖注入,ng想要推崇一种声明式的开发方式,即当我们需要使用某一模块或服务时,不需要关心此模块内部如何实现,只需声明一下就可以使用了。在多处使用只需进行多次声明,大大提高可复用性。

  比如我们的controller,在定义的时候用到一个$scope参数。

app.controller('testC',function($scope){});  

如果我们在此处还需操作其他的东西,比如与浏览器地址栏进行交互。我们只需再多添

一个参数$location进去:

app.controller('testC',function($scope,$location){});  

这样便可以通过$location来与地址栏进行交互了,我们仅仅是声明了一下,所需的其他代码,框架已经帮我们注入了。我们很明显的感觉到了这个函数已经不是常规意义上的javascript函数了,在常规的函数中,把形参换一个名字照样可以运行,但在此处若是把$scope换成别的名字,程序便不能运行了。因为这是已经定义好的服务名称。

这便是依赖注入机制。顺理成章的推断,我们可以自己定义模块和服务,然后在需要的地方进行声明,由框架来替我们注入。

来看下我们如何定义一个服务:

app.factory('tpls',function(){

return ['tpl1','tpl2','tpl3','tpl4'];

});  

看上去相当简单,是因为我在这里仅仅是直接返回一个数组。在实际应用中,这里应该是需要向服务器发起一个请求,来获取到这些模板们。服务的定义方式有好几种,包括使用provider方法、使用factory方法,使用service方法。它们之间的区别暂且不关心。我们现在只要能创建一个服务出来就可以了。我使用了factory方法。一个需要注意的地方是,框架提供的服务名字都是由$开头的,所以我们自己定义的最好不要用$开头,防止发生命名冲突。

定义好一个服务后,我们就可以在控制器中声明使用了,如下:

app.controller('testC',function($scope,tpls){

$scope.question = questionModel;

$scope.nowTime = new Date().valueOf();

$scope.templates = tpls; //赋值到$scope中

$scope.addOption = function(){

var o = {content:''};

$scope.question.options.push(o);

};

$scope.delOption = function(index){

$scope.question.options.splice(index,1);

};

});  

此时,若在模板中书写如下代码,我们便可以获取到服务tpls所提供的数据了:

模板:

<a href="javascript:void(0);" target="_blank" rel="nofollow">

4.9路由route

在谈路由机制前有必要先提一下现在比较流行的单页面应用,就是所谓的single page APP。为了实现无刷新的视图切换,我们通常会用ajax请求从后台取数据,然后套上HTML模板渲染在页面上,然而ajax的一个致命缺点就是导致浏览器后退按钮失效,尽管我们可以在页面上放一个大大的返回按钮,让用户点击返回来导航,但总是无法避免用户习惯性的点后退。解决此问题的一个方法是使用hash,监听hashchange事件来进行视图切换,另一个方法是用HTML5的history API,通过pushState()记录操作历史,监听popstate事件来进行视图切换,也有人把这叫pjax技术。基本流程如下:

如此一来,便形成了通过地址栏进行导航的深度链接(deeplinking ),也就是我们所需要的路由机制。通过路由机制,一个单页应用的各个视图就可以很好的组织起来了。

4.9.1 ngRoute内容

  ng的路由机制是靠ngRoute提供的,通过hash和history两种方式实现了路由,可以检测浏览器是否支持history来灵活调用相应的方式。ng的路由(ngRoute)是一个单独的模块,包含以下内容:

l 服务$routeProvider用来定义一个路由表,即地址栏与视图模板的映射

l 服务$routeParams保存了地址栏中的参数,例如{id : 1, name : 'tom'}

l 服务$route完成路由匹配,并且提供路由相关的属性访问及事件,如访问当前路由对应的controller

l 指令ngView用来在主视图中指定加载子视图的区域

 以上内容再加上$location服务,我们就可以实现一个单页面应用了。下面来看一下具体如何使用这些内容。

4.9.2 ng的路由机制

  第一步:引入文件和依赖

  ngRoute模块包含在一个单独的文件中,所以第一步需要在页面上引入这个文件,如下:

<script src="http://code.angularjs.org/1.2.8/angular.min.js" rel="nofollow"/>

<script src="http://code.angularjs.org/1.2.8/angular-route.min.js" rel="nofollow"/>  

光引入还不够,我们还需在模块声明中注入对ngRoute的依赖,如下:

var app = angular.module('MyApp', ['ngRoute']);  

完成了这些,我们就可以在模板或是controller中使用上面的服务和指令了。下面我们需要定义一个路由表。

  第二步:定义路由表

  $routeProvider提供了定义路由表的服务,它有两个核心方法,when(path,route)和otherwise(params),先看一下核心中的核心when(path,route)方法。

  when(path,route)方法接收两个参数,path是一个string类型,表示该条路由规则所匹配的路径,它将与地址栏的内容($location.path)值进行匹配。如果需要匹配参数,可以在path中使用冒号加名称的方式,如:path为/show/:name,如果地址栏是/show/tom,那么参数name和所对应的值tom便会被保存在$routeParams中,像这样:{name : tom}。我们也可以用*进行模糊匹配,如:/show*/:name将匹配/showInfo/tom。

  route参数是一个object,用来指定当path匹配后所需的一系列配置项,包括以下内容:

l controller //function或string类型。在当前模板上执行的controller函数,生成新的scope;

l controllerAs //string类型,为controller指定别名;

l template //string或function类型,视图z所用的模板,这部分内容将被ngView引用;

l templateUrl //string或function类型,当视图模板为单独的html文件或是使用了<script type="text/ng-template">定义模板时使用;

l resolve //指定当前controller所依赖的其他模块;

l redirectTo //重定向的地址。

最简单情况,我们定义一个html文件为模板,并初始化一个指定的controller:

function emailRouteConfig($routeProvider){

$routeProvider.when('/show', {

controller: ShowController,

templateUrl: 'show.html'

}).

when('/put/:name',{

controller: PutController,

templateUrl: 'put.html'

});

};  

otherwise(params)方法对应路径匹配不到时的情况,这时候我们可以配置一个redirectTo参数,让它重定向到404页面或者是首页。

  第三步:在主视图模板中指定加载子视图的位置

  我们的单页面程序都是局部刷新的,那这个“局部”是哪里呢,这就轮到ngView出马了,只需在模板中简单的使用此指令,在哪里用,哪里就是“局部”。例如:

<div ng-view></div>  或:<ng-view></ng-view>  

我们的子视图将会在此处被引入进来。完成这三步后,你的程序的路由就配置好了。

4.9.3 路由示例

下面我们将用一个例子(例09)来说明路由的使用方式及步骤:

1.为demoApp添加一个路由,代码如下:

demoApp.config(['$routeProvider',function($routeProvider) {

$routeProvider.when('/list', {

templateUrl: 'route/list.html',

controller: 'routeListController'

}).when('/list/:id', {

templateUrl: 'route/detail.html',

controller: 'routeDetailController'

}).otherwise({

redirectTo: '/list'

});

}]);

/list 对应为:route/list.html页面,显示用户列表;/list/:id对应于route/detail.html页面,显示用户详细信息。

2.为list.html和detail.html分别声明Controller:routeListController和routeDetailController。

demoApp.controller('routeListController',function($scope) {

$scope.users = [{userId:"zhangsan",userName:"张三",userInfo:"我是张三,我为自己带盐!"},

{userId:"lisi",userName:"李四",userInfo:"我是李四,我为卿狂!"},

{userId:"woshishui",userName:"我是谁",userInfo:"我是谁!我是谁!我是谁!"}];

});

demoApp.controller('routeDetailController',function($scope, $routeParams, userService) {

$scope.userDetail = userService.getUser($routeParams.id);

});

routeDetailController中如上面提到的一样,注入了userService服务,在这里直接拿来用。

3.创建list.html和detail.html页面,代码如下:

<hr/>

<h3>Route : List.html(用户列表页面)</h3>

<ul>

<li ng-repeat="user in users">

<a href="http://m.cnblogs.com/142260/3817063.html?full=1#/list/{{ user.userId }}" target="_blank" rel="nofollow">

</li>

</ul>

<hr/>

<h3>Route : detail.html(用户详细信息页面)</h3>

<h3>用户名:<span style="color: red;">{{userDetail.userName}}</span></h3>

<div>

<span>用户ID:{{userDetail.userId}}</span><span>用户名:{{userDetail.userName}}</span>

</div>

<div>

用户简介:<span>{{userDetail.userInfo}}</span>

</div>

<div>

<a href="http://m.cnblogs.com/142260/3817063.html?full=1#/list" target="_blank" rel="nofollow">返回</a>

</div>

4. 路由局部刷新位置:

<h1>AngularJS路由(Route) 示例</h1>

<div ng-view></div>

4.10 NG动画效果

4.10.1 NG动画效果简介

NG动画效果,现在可以通过CSS3或者是JS来实现,如果是通过JS来实现的话,需要其他JS库(比如JQuery)来支持,实际上底层实现还是靠其他JS库,只是NG将其封装了,

使其更易使用。

NG动画效果包含以下几种:

  • enter:元素添加到DOM中时执行动画;
  • leave:元素从DOM删除时执行动画;
  • move:移动元素时执行动画;
  • beforeAddClass:在给元素添加CLASS之前执行动画;
  • addClass:在给元素添加CLASS时执行动画;
  • beforeRemoveClass:在给元素删除CLASS之前执行动画;
  • removeClass:在给元素删除CLASS时执行动画。

其相关参数为:

var ngModule = angular.module('YourApp', ['ngAnimate']);

demoApp.animation('.my-crazy-animation', function() {

return {

enter: function(element, done) {

//run the animation here and call done when the animation is complete

return function(cancelled) {

//this (optional) function will be called when the animation

//completes or when the animation is cancelled (the cancelled

//flag will be set to true if cancelled).

};

},

leave: function(element, done) { },

move: function(element, done) { },

//animation that can be triggered before the class is added

beforeAddClass: function(element, className, done) { },

//animation that can be triggered after the class is added

addClass: function(element, className, done) { },

//animation that can be triggered before the class is removed

beforeRemoveClass: function(element, className, done) { },

//animation that can be triggered after the class is removed

removeClass: function(element, className, done) { }

};

});

4.10.2 动画效果示例

下面我们来看下DEMO中的例子(例10)。

1.首先,我们在demoApp下定义一个动画效果,匹配CLASS:” .border-animation”

/*定义动画*/

demoApp.animation('.border-animation', function(){

return{

beforeAddClass : function (element, className, done) {

$(element).stop().animate({

'border-width':1

},2000, function() {

done();

});

},

removeClass : function (element ,className ,done ) {

$(element).stop().animate({

'border-width':50

},3000, function() {

done();

});

}

};

});

动画效果的含义就是:在匹配CLASS为border-animation的元素添加一个CLASS之前使其边框的宽度在2秒内变为1PX;并在其移除一个CLASS时使其边框的宽度在3秒内变为50PX。

2. 视图中的代码如下(主要,其他相关样式请查看例子代码):

<div class="border-animation" ng-show="testShow"></div>

<a href="javascript:void(0);" target="_blank" rel="nofollow">

ng-show为false时会为其加上“ng-hide“的CLASS; ng-show为true时会为其移除“ng-hide“的CLASS,从而触发动画效果。

3.其他代码:

demoApp.controller("test10Controller", function($scope, $animate){

$scope.testShow = true;

});