好,继续上一章节我们继续聊聊angularjs骨架。开发任何一款优秀的应用都会面临一项非常困难的工作,那就是找到一种合适的方式方法把代码组织在合适的功能范围内。我们已经看过控制器的处理方式,它会提供一块空间,把正确的数据模型和函数暴露给视图模版。但是用来支持我们应用的代码该怎么办呢?有一块最明显的可以放在这些代码的地方,那就是控制器的函数。

  这种做法对于小型的应用和例子来说可以工作的很好,我们已经看到过很多这样的例子,但是在真实的应用中,这种做法很快就会使得代码无法维护。控制器将会变成一个垃圾场,我们做的所有东西都会倒在里面。它们会变得非常难以理解,并且很难修改。

  我们来看模块

  我们来看模块,它们提供了一种方法,可以用来组织应用中一块功能区域的依赖关系;同时还提供了一种机制,可以自动解析依赖关系(又叫做依赖注入)。一般来说,我们把这些东西叫做依赖服务。因为它们负责为应用提供特殊服务。

  例如,我们要在购物站点中的一个控制器中需要从服务器上获取一个商品列表,那么我们就需要这些对象——不妨把它叫做Items——用来处理服务器端获取商品列表的工作,进而,Items对象就需要以某种方式与服务器上的数据库进行交互,可以通过XHR或者WebSocket。

  如果没有模块的情况下,我们的控制器看起来可能就是这样:

  

  function ItemsViewController(){
//向服务器发起请求 //解析响应并放入Items对象 //把Items数组放到$scope上,这样视图才能显示它
}

  虽然这样可以运行,但是却存在大量潜在的问题:

  1、如果其他控制器也要从服务器上获取Items,那么只能把这段代码再写一遍,这会给维护工作带来很大的负担。

  2、加上一些其他因素,例如服务端认证、解析数据的复杂性,会使得控制器对象很难划分出一个合理的功能边界,并且代码阅读起来非常困难。

  3、使得单元测试变得复杂。

  利用模块和模块内置的依赖注入的功能,就可以把控制器变得简单,示例如下:

  

 app.controller('myController', function ($scope,Items) {
$scope.items =Items.query();
……
}

   你可能会问,“不错,看起来还不错,但是Items是什么东西,从哪里来?”以上代码,假如我们已经把Items变成了一个服务。服务都是单例的对象,它们用来执行必要的任务支撑应用的功能。

  Angular内置了很多服务,例如$location服务,用来和浏览器的地址栏进行交互;$route服务,用来根据URL地址的变化切换视图;还有$http服务,用来和服务器进行交互。你也可已创建自己的服务,用它们来实现你的应用所特有的功能,如果需要,服务可以在任何控制器中共享,当你需要多个控制器之间进行交互和共享状态时这些服务就是一种很好的机制。Angular的内置服务一$开头,你当然可以为你的服务随意起名字,但是最好不要以$开头,以免引起命名冲突。你可以使用模型对象的API来定义服务。一下三种函数可以用来创建一般的服务,它们的复杂度和功能度不同。

  函数1:provider(name,Object or constructor()),定义:一个可配置的服务,创建的逻辑比较复杂。

  函数2:factory(name,$getFunction() ),定义:一个不可配置的服务,创建逻辑比较复杂。可以把它看成provider(name,{$get:$getFunction()})。

  函数3:servive(name,conttuctor()),定义:一个不可配置的服务,创建逻辑比较简单。

  我们先来看一个使用factory创建服务的例子。我们可以像下面这样来编写服务:

  

 var app = angular.module('MyApp', []);
app.factory('Items', function () {
var items={};
items.query= function () {
return [
{title: "羽毛球", quantity: 8, price: 3.99},
{title: "篮球", quantity: 17, price: 1.99},
{title: "足球", quantity: 5, price: 3.99}
];
};
return items;
});

  为了能让这一机制能够和模版配合起来,我们把模版名称告诉ng-app指令。  

  完整代码如下:

  

 <!DOCTYPE html>
<html ng-app="MyApp">
<head>
<meta charset="UTF-8">
<title></title>
<script src="static/js/angular.js" type="text/javascript"></script>
<script src="static/app/controller/shopingcartcontroller.js" type="text/javascript"></script>
</head>
<body ng-controller="myController">
<div>
<h1>Your Shoping Cart</h1>
<div ng-repeat="item in items">
<span>{{item.title}}</span>
<input type="text" ng-model="item.quantity"/>
<span>{{item.quantity | currency}}</span>
<span>{{item.quantity * item.price | currency}}</span>
<button ng-click="remove($index)">remove</button>
</div> <div>total:{{bill.totalCart| currency}}</div>
<div>Discount:{{bill.discount | currency}}</div>
<div>Subtotal:{{ bill.subtotal | currency}}</div>
</div>
</body>
</html>
 /**
* Created by Administrator on 2015/6/12.
*/
var app = angular.module('MyApp', []);
app.factory('Items', function () {
var items={};
items.query= function () {
return [
{title: "羽毛球", quantity: 8, price: 3.99},
{title: "篮球", quantity: 17, price: 1.99},
{title: "足球", quantity: 5, price: 3.99}
];
};
return items;
});
app.controller('myController', function ($scope,Items) {
$scope.bill = {};
$scope.items =Items.query(); $scope.remove = function (index) {
$scope.items.splice(index, 1);
} //var calulateTotal = function () {
// var total = 0;
// for (var i = 0, len = $scope.items.length; i < len; i++) {
// total = total + $scope.items[i].price * $scope.items[i].quantity;
// }
// $scope.bill.totalCart = total;
// $scope.bill.discount = total > 100 ? 10 : 0;
// $scope.bill.subtotal=total - $scope.bill.discount;
//}; $scope.$watch(function () {
var total = 0;
for (var i = 0, len = $scope.items.length; i < len; i++) {
total = total + $scope.items[i].price * $scope.items[i].quantity;
}
$scope.bill.totalCart = total;
$scope.bill.discount = total > 100 ? 10 : 0;
$scope.bill.subtotal=total - $scope.bill.discount;
}); function ItemsViewController(){
//向服务器发起请求 //解析响应并放入Items对象 //把Items数组放到$scope上,这样视图才能显示它
}
});

  

  当然你如果你需要使用第三个方包中的所提供的服务或指令,它们一般会有自己的模块,所以需要在应用中定义依赖关系才能应用它们。假如你引入了模块A和B,那么应用中 的模块声明看起来可能会像下面这样:

  var appMod=agular.module('myapp',['A','B']);

  

  使用过滤器格式化数据

  你可以使用过滤器来声明如何变换数据显示的格式,然后在展示给用户,你只要在模版中使用一个插值变量即可。使用过滤器的语法是:

  {{expression | filterName : parameter1 : parameter2}}

  过滤器中的多个参数使用冒号隔开。

  Angular中有很多过滤器,如currency

  {{12.9 | currency}}

  以上代码得到结果就是$12.90

  在绑定过程中使用管道符号把过滤器连接起来。例如:

  {{12.9 | currency | number}}

  得到的结果是$13

  当然,你也不必受限与内置过滤器,你也可以自定义过滤器:

  

   <p> {{ 'my name is amber.xu' | titleCase }}</p>
 app.filter('titleCase', function () {
var titleCaseFilter= function (input) {
var words=input.split(' ');
for(var i=0;i<words.length;i++){
words[i]=words[i].charAt(0).toUpperCase() + words[i].slice(1);
}
return words.join(' ');
};
return titleCaseFilter;
});

效果如下:

  My Name Is Amber.xu

  

  使用路由和$location切换视图

  虽然从技术上来说AJAX应用确实是单页应用,但是在很多时候,出于各种原因,我们需要为用户展示或隐藏一些子页面视图。

  我们可以利用angular的$route服务来管理这种场景,可以利用路由服务来定义这样一种东西:对于浏览器的一种url,angular将会加载一中视图模版,并实例化一个控制器为模版提供内容。在应用中你可以使用$routeProvider服务上的函数来创建路由,把需要创建的路由当成一个配置块来传给函数即可。创建过程类似一下的伪代码:

  

 app.config(function ($routeProvider) {
$routeProvider.when('url',{controller:aController,templateUrl:'/path/to/template'}).
when(...other mapping for your app...).
...
otherwise(...waht to do if nothing else matches...)
});

  以上代码是说,当浏览器中的URL发生变成指定的取值时,angular将会加载/path/to/template路径下的模版,然后把模版中的跟元素关联到aController上(因为我们在模版中写了ng-controller=aController)最后一行的otherwise相当于else或者default。

  既然,理论上的东西都有了。我们来实战一下吧。我写这个demo的时候也遇到了一些bug,不妨爆出来给大家看看:

  错误1:

  

这个错出现的原因是说$routeProvider根本没有被找到,为什么会没有被找到了,你可能会说,我已经导入了angular.js文件啦?其实不然,路由已经被单独分离出来了,所以要导入angular-route.js文件的引用,之前有讲过,如果使用了第三方包中提供的指令就要在模块中引用它:var app=angular.module('AMail',['ngRoute']);如果值导入了文件,而在代码中没有对ngRoute进行引用会出现此错误:

现在需要一个首页index.html

 <!DOCTYPE html>
<html ng-app="AMail">
<head>
<meta charset="UTF-8">
<title>AMail</title>
<script src="../static/js/angular.js" type="text/javascript"></script>
<script src="../static/js/angular-route.min.js"></script>
<script src="../static/app/controller/controller.js" type="text/javascript"></script>
</head>
<body>
<h1>A-Mail</h1>
<div ng-view> </div>
</body>
</html>

index.html上有一个之前没有见过的指令ng-view。ng-view会把模版中的内容替换到这里(相当于一个占位符,说的比较口语化)。

有两个模版

1、list.html显示所有的邮件列表。

2、detail.html单个邮件的详细页。

 <table>
<tr>
<td><strong>Sender</strong></td>
<td><strong>Subject</strong></td>
<td><stroong>Date</stroong></td>
</tr>
<tr ng-repeat="message in messages">
<td>{{message.sender}}</td>
<td><a href="#/view/{{message.id}}">{{message.subject}}</a></td>
<td>{{message.date}}</td>
</tr>
</table>

list.html

 <div><strong>Subject:</strong>{{message.subject}}</div>
<div><strong>Sender:</strong>{{message.sender}}</div>
<div><strong>Date:</strong>{{message.date}}</div>
<div><strong>To:</strong>
<span ng-repeat="re in message.recipients"> {{re}}</span>
</div>
<div>{{message.message}}</div>
<a href="#/">Back to Message</a>

detail.html

 !(function () {
var app = angular.module('AMail', ['ngRoute']); function emailRouteCoinfig($routeProvider) {
$routeProvider.when('/', {controller: ListController, templateUrl: 'list.html'}).
when('/view/:id', {controller: DetailController, templateUrl: 'detail.html'}).
otherwise({redirectTo: '/'});
};
//配置我们的路由,以便AMail能够找到他
app.config(emailRouteCoinfig); //一些虚拟的哟意见
var messages = [
{
id: 0,
sender: 'jean@yesno.com.cn',
subject: '今天不用加班啦,明天周末',
date: '2015年7月14日 21:39:59',
message: '今天不用加班啦,明天周末!明天是周末,可以好好休息两天了。',
recipients: ['woshixuleijava@163.com']
},
{
id: 1,
sender: 'jean2@yesno.com.cn',
subject: '明天不用加班啦,明天周末',
date: '2015年7月15日 21:39:59',
message: '明天不用加班啦,明天周末!明天是周末,可以好好休息两天了。',
recipients: ['woshixuleijava2@163.com']
},
{
id: 2,
sender: 'jean3@yesno.com.cn',
subject: '后天不用加班啦,明天周末',
date: '2015年7月16日 21:39:59',
message: '后天不用加班啦,明天周末!明天是周末,可以好好休息两天了。',
recipients: ['woshixuleijava3@163.com']
}
]; function ListController($scope) {
$scope.messages = messages;
};
function DetailController($scope, $routeParams) {
$scope.message = messages[$routeParams.id];
}; }());

controller.js

  效果图:

  

  

我们已经为应用搭好了基本框架,这款应用带有很多视图,可以通过修改url的方式来切换视图。这就意味着对用户来说,前进后退按钮能真正运行起来了。而这里实际上只有一个真实的HTML页面。  

angularjs应用骨架(3)的更多相关文章

  1. angularjs应用骨架(2)

    时隔一个星期,接着上一篇的angularjs应用骨架继续聊聊angularjs其他的其他的内容. 区分UI和控制器的职责 在应用控制器中有三种职责: 1.为应用中模型设置初始状态 2.通过$scope ...

  2. angularjs应用骨架

    使用典型的类库时,你可以选择并使用你所喜欢的功能:而对于angularjs框架来说,必须把它看成一个完整的套件来使用,框架中的所有的东西都包含在里面,接下来将会介绍angular的基础模块,这样你就可 ...

  3. angularjs应用骨架(4)

    继续上一篇 继续了解angular其他内容. 与服务器交互 真正的应用需要和真实的服务器进行交互移动应用和新兴的Chrome桌面应用可能是例外.但是对于此外的所有应用来说,无论是想把数据持久化到云端还 ...

  4. 用angularjs开发下一代web应用(二):angularjs应用骨架(二)

    1.浅谈非入侵式JavaScript <div ng-click="doSomething()">...</div>这些指令和原来的事件处理器有下面不同之处 ...

  5. 【AngularJS】【02】AngularJS应用骨架

    ※文件引自OneDrive,有些人可能看不到

  6. AngularJs 基础(60分钟入门)

    AngularJS 是一个创建富客户端应用的JavaScript MVC框架.你仍然需要具有服务端后台,但大多数的用户交互逻辑将放到客户端上处理.它可以创建单页的应用程序,一个页面的应用仅仅需要HTM ...

  7. AngularJS 中文资料+工具+库+Demo 大搜集

    中文学习资料: 中文资料且成系统的就这么多,优酷上有个中文视频. http://www.cnblogs.com/lcllao/archive/2012/10/18/2728787.html   翻译的 ...

  8. 用AngularJS开发下一代Web应用 系列入门基础教程

    开篇介绍 AngularJS是什么东西?我觉得不用再描述了.可自行去充电一下.按照惯例,让我们先看看一个Hello World的开门简介吧. <!doctype html> <htm ...

  9. AngularJs 基础(60分钟入门) (转)

    AngularJs是一个不错的用于开发SPA应用(单页Web应用)的框架.单页Web应用(single page web application,SPA),就是只有一张Web页面的应用.浏览器一开始会 ...

随机推荐

  1. Bzoj 1687: [Usaco2005 Open]Navigating the City 城市交通 广搜,深搜

    1687: [Usaco2005 Open]Navigating the City 城市交通 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 122  So ...

  2. Hadoop之hive安装过程以及运行常见问题

    Hive简介 1.数据仓库工具 2.支持一种与Sql类似的语言HiveQL 3.可以看成是从Sql到MapReduce的映射器 4.提供shall.Jdbc/odbc.Thrift.Web等接口 Hi ...

  3. Cas Server中各配置文件介绍

    Cas Server中所有的配置文件都是放在WEB-INF目录及其子目录下的. 在WEB-INF/classes下的配置文件有: l  cas-theme-default.properties:该文件 ...

  4. Windows下安装Eric5时出现的“Sorry, please install QtHelp.”问题解决办法

    解决Windows下安装Eric5时出现的“Sorry, please install QtHelp.”问题   PyQt4在Windows中使用了DirectX作为加速,不过,PyQt4没有使用最新 ...

  5. 三种排序算法python源码——冒泡排序、插入排序、选择排序

    最近在学习python,用python实现几个简单的排序算法,一方面巩固一下数据结构的知识,另一方面加深一下python的简单语法. 冒泡排序算法的思路是对任意两个相邻的数据进行比较,每次将最小和最大 ...

  6. json xmpp

    https://github.com/lamfire/jspp http://blog.csdn.net/nomousewch/article/category/823687 http://my.os ...

  7. Windows XP下安装WinCE6.0开发环境

    Windows下怎样编译WinCE6.0及开发应用程序.以下介绍(安装之前必须保证C盘有足够的空间!20g左右!主要是由于在安装程序在安装过程中要解压): 在Visual Studio 2005之前, ...

  8. android 5.0开发环境搭建

    Android 5.0 是 Google 于 2014 年 10 月 15 日发布的全新 Android 操作系统.本文将就最新的Android 5.0 开发环境搭建做详细介绍. 工具/原料 jdk- ...

  9. hibernate.hbm.xml配置文件内容说明

    下面是一个自动生成的配置文件: <?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE hibernate-configuration PU ...

  10. Linux下搭建Oracle11g RAC(3)----创建用户及配置相关文件

    配置11gR2 RAC需要安装Oracle Grid Infrastructure软件.Oracle数据库软件,其中Grid软件等同于Oracle 10g的Clusterware集群件.Oracle建 ...