angularjs 登录例子可不可以类型转换呀?可以的话给个小例子!!!谢谢了

谁有《童话转个弯》小说的电子版,可不可以给我?谢谢!!!找了好几天了!_百度知道
谁有《童话转个弯》小说的电子版,可不可以给我?谢谢!!!找了好几天了!
我有更好的答案
百度私信你了,有这本的PDF版,作者:其莎著
采纳率:77%
为您推荐:
其他类似问题
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。AngularJS 为什么如此火呢? - 文章 - 伯乐在线
& AngularJS 为什么如此火呢?
【伯乐在线注】:上周我们在推荐了英文原文,感谢 的翻译分享。如果其他朋友也有不错的原创或译文,可以尝试。
在本文中让我们来逐步发掘angular为什么如此火:
AngularJS是一个MV*(Model-View-Whatever,不管是MVC或者MVVM,统归MDV(model Drive View))JavaScript框架,其是Google推出的SPA(single-page-application)应用框架,其为我们的web应用开发增加不少魔法变换。
我可以花整天的时间告诉你为什么你必须在新项目尝试angular.js,但是我觉得还是百说不如一练。
数据绑定和scopes(作用域)
首先第一个浮出大脑的问题是:angular支持数据绑定吗?下面让我们来了解angular.js的数据绑定:
&body ng-app&
&span&Insert your name:&/span&
&input type="text" ng-model="user.name" /&
&h3&Echo: {{user.name}}&/h3&
&body ng-app&&&&span&Insert your name:&/span&&&&input type="text" ng-model="user.name" /&&&&h3&Echo: {{user.name}}&/h3&&/body&
在这代码片段中,在我们解释细节之前,我还是希望尝试下其效果:
注:此刻暂时不要太心急去了解ng-app。
如你所见,我在input中输入的将会显示在后边echo。这是如何工作的?简单来说,angular的ng-model(更多关于指令的将在文章后续)给我带来了双向绑定机制。
如此是好,但是user.name存储在哪里呢?其存储在我们的$scope上,当我们在input中输入任何字符都会及时的更新scope对象上的user.name属性。然后我们可以利用angular的表达式{{…}}现实在HTML中。所以当我们在input中输入时,其会及时更新scope上的user,name属性,在由修改HTML显示。
好吧,这并不难,但是你所说的$scope是个什么东东呢?在angular中$scope是连接controllers(控制器)和templates(模板view/视图)的主要胶合体。我们可以把我们的model存放在scope上,来达到双向你绑定。
这就好比:
这意味着我们我们从template上为$scope设置了一个属性对象user.name,所以我们也可以在controller中访问这个对象(user.name).
让我们来看个更复杂的示例:
JavaScript
var app = angular.module('app', []);
app.controller('MainCtrl', function($scope) {
$scope.message = 'World';
var app = angular.module('app', []);&app.controller('MainCtrl', function($scope) {&&$scope.message = 'World';});
body ng-app="app" ng-controller="MainCtrl"&
Hello, {{ message }}
body ng-app="app" ng-controller="MainCtrl"&&&Hello, {{ message }}&/body&
在这里首先我们定义了angular application,只是简单的创建了一个angular module,其接受一个module名字和依赖数组为参数。
紧接着创建了一个controller,通过调用 app module的controller方法,并传入一个controller 名字和function。function函数接受$scope参数(可以接受更多的参数,放在后面部分)。所以我们可以开始双向绑定了。
在$scope中我们附加了message的字符串属性。
在view中你可能注意到了body tag多出了一些东东,这是干什么的?这些是angular的指令(directives),它给HTML带来了新的语法扩展,在这例子中我们使用了两个angular内置的指令:
ng-app:它会告诉angularbody节点包含了我们的angular应用,换句话说,在body中的一切会被angular所接受管理。其参数为我们的app module的名字,和我们在javascript中命名一致。
ng-controller:在这指令在我们传入的是controller 名字,此例中为MainCtrl。
最后我们将message插入我们的remplate。
所以其可视化表示将是:
聪明的你可以冒出一个疑问:我们能够在$scope上绑定function?当然。
JavaScript
var app = angular.module('app', []);
app.controller('MainCtrl', function($scope) {
$scope.greet = function() {
$scope.message = "Hello, " + $scope.user.
var app = angular.module('app', []);&app.controller('MainCtrl', function($scope) {&&$scope.greet = function() {&&&&$scope.message = "Hello, " + $scope.user.name;&&}});
&body ng-app="app" ng-controller="MainCtrl"&
What's your name?:
&input type="text" ng-model="user.name" /&
&button ng-click="greet()"&Click here!&/button&
&h3&{{ message }}&/h3&
&body ng-app="app" ng-controller="MainCtrl"&&&What's your name?:&&&input type="text" ng-model="user.name" /&&&&button ng-click="greet()"&Click here!&/button&&&&h3&{{ message }}&/h3&&/body&
我在示例controller中很容易了解到如何添加function到$scope。示例中function将修改$scope.message为“hello ,”和从input输入的$scope.user.name的字符串连接。
然后在HTML中创建一个附加了angular ng-click 指令的button。ng-click指令是的button在被点击时会执行我们为其赋值的greet()表达式。
注意:在input中enter并不会工作,这是展示ng-click如何工作。
我们已经看见了一些指令了,指令是个什么东东?指令为HTML引入了新的语法。HTML已经很强大了,但是有时我需要更多…
看下面的例子:
&div id="chart"&&/div&
&body&&& &div id="chart"&&/div&&/body&
示例代码在做什么?除了看见id外,我真的什么也不能获知。
然后我们只得从多余30个javascript文件中去查找,最后我们看见如下代码:
JavaScript
$('#chart').pieChart({ ... });
$('#chart').pieChart({ ... });
Aha!原来是个饼图(pie chart)容器。
在这里如果你不去查找javascript文件将无法获知页面到底是做什么的,实现了什么功能。
下面我们再来看看angular code,
&pie-chart width="400" height="400" data="data"&&/pie-chart&
&body&&&&&&pie-chart width="400" height="400" data="data"&&/pie-chart&&/body&
是不是语义很清晰,我们可以一眼看出这是一个pie chart,不仅如此,而且还知道width,height,以及其数据。
如果你对pie chart 示例感兴趣,请猛击
angular内置指令
angular给我带来了大量的内置指令。我们已经在前面看见了ng-app,ng-controller,ng-click,ng-model(angular的内置指令都以ng开始),接下来让我了解更多的内置指令。
有时在页面中有部分内容我们只希望到达某状态(属性为true)才显示:
&button ng-click="show = !show"&Show&/button&
&div ng-show="show"&
I am only visible when show is true.
&button ng-click="show = !show"&Show&/button&&&div ng-show="show"&&&&&I am only visible when show is true.&/div&
ng-show仅当angular其表达式值为true时,才显示该元素或子元素。
注意:在这里对于ng-click我们并不是直接在controller中创建function(此刻我们没真正的controller),利用angular表达式作为指令的参数。在首次表达式为undefined,然后我们设置为为true,在false如此交替。
angular同时也提供了ng-hide指令。
让我们看些更有趣的指令,如果有个List或者数组呢?
JavaScript
var app = angular.module('app', []);
app.controller('MainCtrl', function($scope) {
$scope.developers = [
name: "Jesus", country: "Spain"
name: "Dave", country: "Canada"
name: "Wesley", country: "USA"
name: "Krzysztof", country: "Poland"
123456789101112131415161718
var app = angular.module('app', []);&app.controller('MainCtrl', function($scope) {&&$scope.developers = [&&&&&&{&&&&&&&&name: "Jesus", country: "Spain"&&&&&&},&&&&&&{&&&&&&&&name: "Dave", country: "Canada"&&&&&&},&&&&&&{&&&&&&&&name: "Wesley", country: "USA"&&&&&&},&&&&&&{&&&&&&&&name: "Krzysztof", country: "Poland"&&&&&&}&&&&];});
&body ng-app="app" ng-controller="MainCtrl"&
&li ng-repeat="person in developers"&
{{person.name}} from {{person.country}}
&body ng-app="app" ng-controller="MainCtrl"& &ul&&& &li ng-repeat="person in developers"&&&&& {{person.name}} from {{person.country}}&& &/li& &/ul&&/body&
棒极了,我们在controller中定义了一个list对象,在HTML用ng-repeat就能简单的显示了。
它是如何工作的?
ng-repeat会为集合中的每一项创建一个新的模板,在示例中有四项数据,将会重复创建下面code四次,
&li ng-repeat="person in developers"&
{{person.name}} from {{person.country}}
&li ng-repeat="person in developers"&&&&&{{person.name}} from {{person.country}}&/li&
每次复制都会创建自己新的scope,我们没有为每项手动创建scope,我们可以把scope理解为其scope,但是在这里我们仍然能够访问父scope。
可视化的展示为:
我们能自定义directive?
当然,我们能以不同粒度方式创建angular的directive,例如modal dialogs accordions, paginators, charts,search from …
angular指令总是与可视化有关?不,我们仍然可以创建一些非可视化的指令集。
让我们来看一个例子吧:
回到我们上面的greet示例:
&body ng-app="app" ng-controller="MainCtrl"&
What's your name?:
&input type="text" ng-model="user.name" /&
&button ng-click="greet()"&Click here!&/button&
&h3&{{ message }}&/h3&
&body ng-app="app" ng-controller="MainCtrl"&&&What's your name?:&&&input type="text" ng-model="user.name" /&&&&&&button ng-click="greet()"&Click here!&/button&&&&&&&&h3&{{ message }}&/h3&&/body&
已经能够很好的工作了,但是我们希望能够在页面初始化的时候光标焦点聚焦在输入框input。jQuery?jQuery提供了focus函数,能够很简单的完成,但是这里是angular教程,所以我们需要以angular way,显得我们更专业些…
同时我们也希望我们的HTML能够有自描述能力(译者注:现代软件开发特别语言语义更重要,如linq,guava,restfull…) ,所以angular directive肯定是个好的选择。
app.directive('focus', function() {
link: function(scope, element, attrs) {
element[0].focus();
app.directive('focus', function() {&&return {&&&&link: function(scope, element, attrs) {&&&&&&element[0].focus();&&&&}&&};});
接下来,我们可以在可以HTML中标注angular directive(angular directive首字母小写驼峰命名,在前台转换为全小写-分割风格)。
directive是angular中最复杂的要点,这里只是最简单的directive而已,如果可能这将放在以后文章,这里并不会深入。
directive需要一个object的返回对象,我们可以定义一些需要关注的属性,在示例中我们返回了一个link的链接函数(link函数主要作为directive的行为绑定), 我们如果需要,也可以替换HTML中模板。
Link function有3个参数(准确应该是是4个)scope,节点element,还有所有HTML attribute iAttrs。在link函数里我们可以绑定click,mouseenter等事件,注册指令行为。
在示例中我们为指令节点使用了focus操作。对element了解更多,你可以移步到。
我们可以很简单的使用指令如下:
&body ng-app="app" ng-controller="MainCtrl"&
What's your name?:
&input type="text" focus ng-model="user.name" /&
&button ng-click="greet()"&Click here!&/button&
&h3&{{ message }}&/h3&
&body ng-app="app" ng-controller="MainCtrl"&&&What's your name?:&&&input type="text" focus ng-model="user.name" /&&&&button ng-click="greet()"&Click here!&/button&&&&h3&{{ message }}&/h3&&/body&
目前我们看见的directive都很简单,如何利用指令渲染上面说的固定模板呢?
JavaScript
app.directive('hello', function() {
restrict: "E",
replace: true,
template: "&div&Hello readers, thank you for coming&/div&"
app.directive('hello', function() {&&return {&&&&restrict: "E",&&&&replace: true,&&&&template: "&div&Hello readers, thank you for coming&/div&"&&}});
这里返回的是带有一些attribute的object。
restrict:指令的使用方式
Attribute 形如:&div foo&&/div&.
Element 形如:&foo&&/foo&
Class 形如: &div class=”foo”&&/div&
CoMment 形如: &!– directive: foo –&
replace:询问是不是需要利用我们的模板替换原来的节点。
template:我们需要append或者replace到原节点的html模板。
directive还有很多的可配置options,如编译compile,template url …
在示例我们不需要行为的绑定,所有没有link function。其使用如下:
&hello&&/hello&
&hello&&/hello&
Filters(过滤器)
假想我们有个购物车的view显示如下:
&span&There are 13 phones in the basket. Total: {{ 1232.12 }}&/span&
&span&There are 13 phones in the basket. Total: {{ 1232.12 }}&/span&
我们如何利用angular表达式显示为货币格式?形如:$1,232.12。
相当简单,angular为我们提供了叫filter得东东,过滤器其好比unix中的管道pipeline。angular同时也内置了货币currency filter。如你所见,我们可以用| 使用filter,这和unix管道模型很相似。我们也可以使用|链接更多的filter。
例如我们可以对开发人员简单排序,在用ng-repeat显示出来:
&li ng-repeat="person in developers | orderBy:'name'"&
{{ person.name }} from {{ person.country }}
&ul&&&&&&li ng-repeat="person in developers | orderBy:'name'"&&&&&{{ person.name }} from {{ person.country }}&&&&&/li&&/ul&
在这里你发现了一些很有趣的事?卫门你可以给filter传递参数!
OrderBy filter会接受一个属性名,并以它进行排序,示例中我们使用 name,如果你希望反序排列,你可以用 -name表示。
马上你可能会冒出你头脑:假想我们不止4个开发人员,有300,并且我们希望通过 name,country过滤呢?
非常简单:
&body ng-app="app" ng-controller="MainCtrl"&
Search: &input ng-model="search" type="text" /&
&li ng-repeat="person in developers | filter:search"&
{{ person.name }} from {{ person.country }}
&body ng-app="app" ng-controller="MainCtrl"&&&&&Search: &input ng-model="search" type="text" /&&&&&&ul&&&&&&li ng-repeat="person in developers | filter:search"&&&&&{{ person.name }} from {{ person.country }}&&&&&/li&&&&&&/ul&&/body&
在示例中请注意我们是如何绑定search.name的,此处利用name 做filtering。filter的参数不会改变,绑定是search对象,会根据我们在input中输入改变,而filter则会找寻search对象中的name属性。
到这里我希望你也像我一样一样兴奋起来了!
下面我们来自定义filter呢?实现单词首字母大写 filter:
app.filter('capitalize', function() {
return function(input, param) {
return input.substring(0,1).toUpperCase()+input.substring(1);
app.filter('capitalize', function() {&&&&return function(input, param) {&&&&return input.substring(0,1).toUpperCase()+input.substring(1);&&&&}});
这里我们自定义了一个filter其接受输入参数input和过滤器参数param的一个函数。
接下来我们将在view使用它:
&span&{{ "this is some text" | capitalize }}&/span&
&span&{{ "this is some text" | capitalize }}&/span&
在文章最后,我们需要再次较少下services。这是一个的维护应用程序功能逻辑部分,他是一个单间模式singleton。
为了保持应用程序的逻辑层次分明,更趋向于将其业务逻辑放到不同的services,保持controller的逻辑只有流程控制和view交互逻辑。
angular内置了很多services,如$http http请求,$q 异步promises编程模式…在这里我们不会讨论angular的内置services,由于有很多的services,并且很难一次性解释完,将在后续文章。我们将创建一个简单的自定义services。
在controller之间共享数据对我们很有用,每个controller都有自己的scope所以我们不能将其绑定到其他的controller。所以解决方案是services,可以吧数据共享到services,在需要用到的地方引用它。
首先我们来看看如果不用services,我们将会遇见什么问题:
&div ng-controller="MainCtrl"&
&input type="text" ng-model="user.name"&
&div ng-controller="SecondCtrl"&
SecondCtrl:
&input type="text" ng-model="user.name"&
&div ng-controller="MainCtrl"&&&&&MainCtrl:&&&&&input type="text" ng-model="user.name"& &/div&&&&&&div ng-controller="SecondCtrl"&&&&&SecondCtrl:&&&&&input type="text" ng-model="user.name"&&/div&
我们使用了相同的ng-model,预期当一个input改变时候会及时更新到另一个input,如下:
但是实际情况却是:
接下来需要借助services来解决这个问题,利用services将user name在controller之间共享。
app.factory('UserInformation', function() {
var user = {
name: "Angular.js"
app.factory('UserInformation', function() {var user = {name: "Angular.js"};return user;});
这里用的是factory去创建一个service。angular中还有其他更高级的方式去创建service,如service,provider,这将会在后续文章详解。
这里有很多方式去创建service,我们选择的是创建了一个带有name默认值的user对象,并返回它。
在controllers中如何去使用呢?如下:
app.controller('MainCtrl', function($scope, UserInformation) {
$scope.user = UserI
app.controller('SecondCtrl', function($scope, UserInformation) {
$scope.user = UserI
app.controller('MainCtrl', function($scope, UserInformation) {$scope.user = UserInformation;});&app.controller('SecondCtrl', function($scope, UserInformation) {$scope.user = UserInformation;});
现在我们的程序形如:
现在我们的$scope.user在MainCtrl和SecondCtrl都用的是UserInformation,并且service是单例的,所以当我们更新其中一个controller的时候,另外一个也将会被更新。也有你又有了一个疑问:UserInformation参数是从哪里来的?
angular核心是DI(依赖注入)在需要使用的地方会自定注入service。DI将不会在本节中讲述,我们可以简单的说,你创建了一个service,你可以在module作用域的controller,directive,甚至是其他service作为参数来轻松使用。
也许你对上面出现的$scope认为他也是个service,其实这是一个例外,其并不是真正的service注入到我们的controller。
到这里我们完成了第一篇但不是最后一篇angular博客。Angular.js是一个优秀的框架,我敢肯定你也爱上了它。希望能在下片文章中仍然能见到你的倩影。希望你能喜欢这篇文章,也能够评论些你的观点。
可能感兴趣的话题
好文!期待更多!!
关于伯乐在线博客
在这个信息爆炸的时代,人们已然被大量、快速并且简短的信息所包围。然而,我们相信:过多“快餐”式的阅读只会令人“虚胖”,缺乏实质的内涵。伯乐在线内容团队正试图以我们微薄的力量,把优秀的原创文章和译文分享给读者,为“快餐”添加一些“营养”元素。
新浪微博:
推荐微信号
(加好友请注明来意)
– 好的话题、有启发的回复、值得信赖的圈子
– 分享和发现有价值的内容与观点
– 为IT单身男女服务的征婚传播平台
– 优秀的工具资源导航
– 翻译传播优秀的外文文章
– 国内外的精选文章
– UI,网页,交互和用户体验
– 专注iOS技术分享
– 专注Android技术分享
– JavaScript, HTML5, CSS
– 专注Java技术分享
– 专注Python技术分享
& 2018 伯乐在线前端技术的发展是如此之快,各种优秀技术、优秀框架的出现简直让人目不暇接,紧跟时代潮流,学习掌握新知识自然是不敢怠慢。
是google在维护,其在国外已经十分火热,可是国内的使用情况却有不小的差距,参考文献/网络文章也很匮乏。这里便将我学习AngularJS写成文档,一方面作为自己学习路程上的记录,另一方面也给有兴趣的同学一些参考。
首先我自己也是一名学习者,会以学习者的角度来整理我的行文思路,这里可能只是些探索,有理解或是技术上的错误还请大家指出;其次我特别喜欢编写小例子来把一件事情说明白,故在文中会尽可能多的用示例加代码讲解,我相信这会是一种比较好的方式;最后,我深知AngularJS的使用方式跟的使用方式有很大不同,在大家都有jquery、ext经验的条件下对于angular的学习会困难重重,不过我更相信在大家的坚持下,能够快速的学好AngularJS,至少咱也能深入了解到AngularJS的基本思想,对咱们以后自己的插件开发、项目开发都会有很大的启示。
2&AngularJS概述
2.1&AngularJS是什么?
AngularJs(后面就简称ng了)是一个用于设计动态web应用的结构框架。首先,它是一个框架,不是类库,是像EXT一样提供一整套方案用于设计web应用。它不仅仅是一个框架,因为它的核心其实是对HTML标签的增强。
何为HTML标签增强?其实就是使你能够用标签完成一部分页面逻辑,具体方式就是通过自定义标签、自定义属性等,这些HTML原生没有的标签/属性在ng中有一个名字:指令(directive)。后面会详细介绍。那么,什么又是动态web应用呢?与传统web系统相区别,web应用能为用户提供丰富的操作,能够随用户操作不断更新视图而不进行url跳转。ng官方也声明它更适用于开发CRUD应用,即数据操作比较多的应用,而非是游戏或图像处理类应用。
为了实现这些,ng引入了一些非常棒的特性,包括模板机制、数据绑定、模块、指令、依赖注入、路由。通过数据与模板的绑定,能够让我们摆脱繁琐的DOM操作,而将注意力集中在业务逻辑上。
  另外一个疑问,ng是MVC框架吗?还是MVVM框架?官网有提到ng的设计采用了MVC的基本思想,而又不完全是MVC,因为在书写代码时我们确实是在用ng-controller这个指令(起码从名字上看,是MVC吧),但这个controller处理的业务基本上都是与view进行交互,这么看来又很接近MVVM。让我们把目光移到官网那个非醒目的title上:“AngularJS&—&Superheroic&JavaScript&MVW&Framework”。
2.2&AngularJS简单介绍
AngularJS&重新定义了前端应用的开发方式。面对HTML和JavaScript之间的界线,它
非但不畏缩不前,反而正面出击,提出了有效的解决方案。
很多前端应用的开发框架,比如Backbone、EmberJS等,都要求开发者继承此框架特有的一些JavaScript对象。这种方式有其长处,但它不必要地污染了开发者自己代码的对象空间,还要求开发者去了解内存里那些抽象对象。尽管如此我们还是接受了这种方式,因为网络最初的设计无法提供&我们今天所需的交互性,于是我们需要框架,来帮我们填补JavaScript和HTML之间的鸿沟。而且有了它,你不用再“直接”操控DOM,只要给你的DOM注上metadata(即AngularJS里的directive们),然后让AngularJS来帮你操纵DOM。同时,AngularJS不依赖(也不妨碍)任何其他的框架。你甚至可以基于其它的框架来开发AngularJS应用。
API地址:;
AngularJS在github上的中文粗译版地址:。
2.3&什么时候该用AngularJS
AngularJS是一个&MV*&框架,最适于开发客户端的单页面应用。它不是个功能库,而是用来开发动态网页的框架。它专注于扩展HTML的功能,提供动态数据绑定(data&binding),而且它能跟其它框架(如jQuery)合作融洽。
如果你要开发的是单页应用,AngularJS就是你的上上之选。Gmail、Google&Docs、Twitter和Facebook这样的应用,都很能发挥AngularJS的长处。但是像游戏开发之类对DOM进行大量操纵、又或者单纯需要&极高运行速度的应用,就不是AngularJS的用武之地了。
3&AugularJS特性
AngularJS是一个新出现的强大客户端技术,提供给大家的一种开发强大应用的方式。这种方式利用并且扩展HTML,CSS和javascript,并且弥补了它们的一些非常明显的不足。本应该使用HTML来实现而现在由它开发的动态一些内容。
AngularJS有五个最重要的功能和特性:
3.1&特性一:双向的数据绑定
数据绑定可能是AngularJS最酷最实用的特性。它能够帮助你避免书写大量的初始代码从而节约开发时间。一个典型的web应用可能包含了80%的代码用来处理,查询和监听DOM。数据绑定是的代码更少,你可以专注于你的应用。
我们想象一下Model是你的应用中的简单事实。你的Model是你用来读取或者更新的部分。数据绑定指令提供了你的Model投射到view的方法。这些投射可以无缝的,毫不影响的应用到web应用中。
传统来说,当model变化了。&开发人员需要手动处理DOM元素并且将属性反映到这些变化中。这个一个双向的过程。一方面,model变化驱动了DOM中元素变化,另一方面,DOM元素的变化也会影响到Model。这个在用户互动中更加复杂,因为开发人员需要处理和解析
这些互动,然后融合到一个model中,并且更新View。这是一个手动的复杂过程,当一个应用非常庞大的时候,将会是一件非常费劲的事情。
这里肯定有更好的解决方案!那就是AngularJS的双向数据绑定,能够同步DOM和Model等等。
这里有一个非常简单的例子,用来演示一个input输入框和&h1&元素的双向绑定(例01):
说明:实际效果请大家看AngularJS/demo/index.html
3.2&特性二:模板
在AngularJS中,一个模板就是一个HTML文件。但是HTML的内容扩展了,包含了很多帮助你映射model到view的内容。
HTML模板将会被浏览器解析到DOM中。DOM然后成为AngularJS编译器的输入。AngularJS将会遍历DOM模板来生成一些指导,即,directive(指令)。所有的指令都负责针对view来设置数据绑定。
我们要理解AuguarJS并不把模板当做String来操作。输入AngularJS的是DOM而非string。数据绑定是DOM变化,不是字符串的连接或者innerHTML变化。使用DOM作为输入,而不是字符串,是AngularJS区别于其它的框架的最大原因。使用DOM允许你扩展指令词汇并且可以创建你自己的指令,甚至开发可重用的组件。
最大的好处是为设计师和开发者创建了一个紧密的工作流。设计师可以像往常一样开发标签,然后开发者拿过来添加上功能,通过数据绑定将会使得这个过程非常简单。
这里有一个例子,我们使用ng-repeat指令来循环图片数组并且加入img模板,如下:
function&AlbumCtrl($scope)&{
&&&&scope.images&=&[
&&&&&&&&{"image":"img/image_01.png",&"description":"Image&01&description"},
&&&&&&&&{"image":"img/image_02.png",&"description":"Image&02&description"},
&&&&&&&&{"image":"img/image_03.png",&"description":"Image&03&description"},
&&&&&&&&{"image":"img/image_04.png",&"description":"Image&04&description"},
&&&&&&&&{"image":"img/image_05.png",&"description":"Image&05&description"}
&div&ng-controller="AlbumCtrl"&
&&&&&li&ng-repeat="image&in&images"&
&&&&&&&img&ng-src="http://m.cnblogs.com/142260/{{image.thumbnail}}" rel="nofollow"/&
这里还有一件事值得提一句,AngularJS并不强制你学习一个新的语法或者从你的应用中提出你的模板。
3.3&特性三:MVC
针对客户端应用开发AngularJS吸收了传统的MVC基本原则。MVC或者Model-View-Controll设计模式针对不同的人可能意味不同的东西。AngularJS并不执行传统意义上的MVC,更接近于MVVM(Moodel-View-ViewModel)。&
model是应用中的简单数据。一般是简单的javascript对象。这里没有必要继承框架的classes,使用proxy对象封装或者使用特别的setter/getter方法来访问。事实上我们处理vanilla&javascript的方法就是一个非常好的特性,这种方法使得我们更少使用应用的原型。
viewmodel是一个用来提供特别数据和方法从而维护指定view的对象。
viewmodel是$scope的对象,只存在于AnguarJS的应用中。$scope只是一个简单的js对象,这个对象使用简单的API来侦测和广播状态变化。
Controller
controller负责设置初始状态和参数化$scope方法用以控制行为。需要指出的controller并不保存状态也不和远程服务互动。
view是AngularJS解析后渲染和绑定后生成的HTML&。这个部分帮助你创建web应用的。$scope拥有一个针对数据的参考,controller定义行为,view处理布局和互动。
3.4&特性四:服务和依赖注入
AngularJS服务其作用就是对外提供某个特定的功能。
AngularJS拥有内建的依赖注入(DI)子系统,可以帮助开发人员更容易的开发,理解和应用。
DI允许你请求你的依赖,而不是自己找寻它们。比如,我们需要一个东西,DI负责找创建并且提供给我们。
为了而得到核心的AngularJS服务,只需要添加一个简单服务作为参数,AngularJS会侦测并且提供给你:
function&EditCtrl($scope,&$location,&$routeParams)&{
&&&&&//&Something&clever&here...
你也可以定义自己的服务并且让它们注入:
angular.module('MyServiceModule',&[]).
&&&&factory('notify',&['$window',&function&(win)&{
&&&&return&function&(msg)&{
&&&&&&&&win.alert(msg);
function&myController(scope,&notifyService)&{
&&&&scope.callNotify&=&function&(msg)&{
&&&&&&&&notifyService(msg);
myController.$inject&=&['$scope',&'notify'];&
3.5&特性五:指令(Directives)
指令是我个人最喜欢的特性。你是不是也希望浏览器可以做点儿有意思的事情?那么AngularJS可以做到。
指令可以用来创建自定义的标签。它们可以用来装饰元素或者操作DOM属性。可以作为标签、属性、注释和类名使用。
这里是一个例子,它监听一个事件并且针对的更新它的$scope&,如下:
myModule.directive('myComponent',&function(mySharedService)&{
&&&&return&{
&&&&&&&&restrict:&'E',
&&&&&&&&controller:&function($scope,&$attrs,&mySharedService)&{
&&&&&&&&&&&&$scope.$on('handleBroadcast',&function()&{
&&&&&&&&&&&&&&&&$scope.message&=&'Directive:&'&+&mySharedService.
&&&&&&&&&&&&});
&&&&&&&&},
&&&&&&&&replace:&true,
&&&&&&&&template:&'&input&'
然后,你可以使用这个自定义的directive来使用:
&my-component&ng-model="message"&&/my-component&
使用一系列的组件来创建你自己的应用将会让你更方便的添加,删除和更新功能。
4&功能介绍
4.1数据绑定
AngularJS的双向数据绑定,意味着你可以在Mode(JS)中改变数据,而这些变动立刻就会自动出现在View上,反之亦然。即:一方面可以做到model变化驱动了DOM中元素变化,另一方面也可以做到DOM元素的变化也会影响到Model。
在我们使用jQuery的时候,代码中会大量充斥类似这样的语句:var&val&=&$(‘#id’).val();&$(‘#id’).html(str);等等,即频繁的DOM操作(读取和写入),其实我们的最终目的并不是要操作DOM,而是要实现业务逻辑。ng的绑定将让你摆脱DOM操作,只要模板与数据通过声明进行了绑定,两者将随时保持同步,最新的数据会实时显示在页面中,页面中用户修改的数据也会实时被记录在数据模型中。
从View到Controller再到View的数据交互(例01):
&html&ng-app="demoApp"&
&input&type="text"&ng-model="user.name"&placeholder="请输入名称"/&
Hello,&{{&user.name&}}!
关键:&ng-app&、&ng-model&和&{&{user.name&}&}&
首先:&&html&元素的ng-app属性。标识这个DOM里面的内容将启用AngularJS应用。
其次:告诉AngularJS,对页面上的“user.name”&这个Model进行双向数据绑定。
第三:告诉AngularJS,在“{{&user.name}}”这个指令模版上显示“user.name”这个Model的数据。
从Server到Controller再到View的数据交互(例02):
&html&ng-app="demoApp"&
&div&&ng-controller="demoController"&
&input&type="text"&ng-model="user.name"&disabled="disabled"/&
&a&href="javascript:void(0);" target="_blank" rel="nofollow"&获取名字&/a&
demoApp.controller("demoController",&function($http,&$scope){
$scope.&getAjaxUser&=&function(){
// $http.get({url:"../xxx.action"}).success(function(data){
// $scope.user=&
$scope.user&=&{"name":"从JOSN中获取的名称","age":22};
改变$scope中的user,View也会自动更新。
4.2&scopes、module、controller&
4.2.1&scopes
$scope是一个把view(一个DOM元素)连结到controller上的对象。在我们的MVC结构里,这个&$scope&将成为model,它提供一个绑定到DOM元素(以及其子元素)上的excecution&context。
尽管听起来有点复杂,但&$scope&实际上就是一个JavaScript对象,controller和view都可以访问它,所以我们可以利用它在两者间传递信息。在这个&$scope&对象里,我们既存储数据,又存储将要运行在view上的函数。
每一个Angular应用都会有一个&$rootScope。这个&$rootScope&是最顶级的scope,它对应着含有&ng-app&指令属性的那个DOM元素。
app.run(function($rootScope)&{&$rootScope.name&=&"张三";&});
如果页面上没有明确设定&$scope&,Angular&就会把数据和函数都绑定到这里,&第一部分中的例子就是靠这一点成功运行的。
这样,我们就可以在view的任何地方访问这个name属性,使用模版表达式{{}},像这样:
{{&name&}}&&
4.2.2&module
首先需要明确一下模板的概念。在我还不知道有模板这个东西的时候,曾经用js拼接出很长的HTML字符串,然后append到页面中,这种方式想想真是又土又笨。后来又看到可以把HTML代码包裹在一个&script&标签中当作模板,然后按需要取来使用。
在ng中,模板十分简单,它就是我们页面上的HTML代码,不需要附加任何额外的东西。在模板中可以使用各种指令来增强它的功能,这些指令可以让你把模板和数据巧妙的绑定起来。
在&html&标签上多了一个属性ng-app=”MyApp”,它的作用就是用来指定ng的作用域是在&html&标签以内部分。在js中,我们调用angular对象的module方法来声明一个模块,模块的名字和ng-app的值对应。这样声明一下就可以让ng运行起来了。
&html&ng-app="demoApp"&
var&demoApp&=&angular.module('demoApp',&[]);
4.2.3&ng-controller
要明确创建一个$scope&对象,我们就要给DOM元素安上一个controller对象,使用的是ng-controller&指令属性:
&div&ng-controller="MyController"&&{{&person.name&}}&&/div&&&
ng-controller指令给所在的DOM元素创建了一个新的$scope&对象,并将这个$scope&对象包含进外层DOM元素的$scope&对象里。在上面的例子里,这个外层DOM元素的$scope&对象,就是$rootScope&对象。这个scope链是这样的:
所有scope都遵循原型继承(prototypal&inheritance),这意味着它们都能访问父scope们。对任何属性和方法,如果AngularJS在当前scope上找不到,就会到父&scope上去找,如果在父scope上也没找到,就会继续向上回溯,一直到$rootScope&上。即如果controller是多层嵌套的,就会从最里面一直往外找,这个scope链是这样的:
唯一的例外:有些指令属性可以选择性地创建一个独立的scope,让这个scope不继承它的父scope们,这个会在指令详解中说明。
$http&服务是AngularJS的核心服务之一,它帮助我们通过XMLHttpRequest对象或JSONP与远程HTTP服务进行交流。
$http&服务是这样一个函数:它接受一个设置对象,其中指定了如何创建HTTP请求;它将返回一个承诺(*参考JavaScript异步编程的promise模式),其中提供两个方法:&success方法和error方法。
demoApp.controller("demoController",&function($http,&$scope){
$scope.&getAjaxUser&=&function(){
$http.get({url:"../xxx.action"}).success(function(data){
alert(data);
}).error(function(){
Alert(“出错了!”);
AngularJS的AJAX与jquery等框架的AJAX基本一致,这里就不多说了。
ng中的表达式与javascript表达式类似但是不可以划等号,它是ng自己定义的一套模式。表达式可以作为指令的值,如ng-modle=”people.name”、ng-click=”showMe()”,看起来是如此像字符串,故而也叫字符串表达式。也可以在标记中使用表达式,如{{1+2}},或者与过滤器一起使用{{1+2&|&currency}}。在框架内部,字符串不会简单的使用eval()来执行,而是有一个专门的$parse服务来处理。在ng表达式中不可以使用循环语句、判断语句,事实上在模板中使用复杂的表达式也是一个不推荐的做法,这样视图与逻辑就混杂在一起了
我们在使用其他模板库时,一般都会有模板的循环输出、分支输出、逻辑判断等类似的控制。
要想理解指令属性的运作,我们必须先理解表达式。在之前的例子里我们已经见过表达式,例如&{{&user.name&}}。
请查看例03、例04、例05。
{{&8&+&1&}} 9
{{&person&}} {"name":"Ari&Lerner"}
{{&10&*&3.3&|&currency&}} $33.00
表达式粗略来看有点像&eval(javascript)&的结果。它们会经过Angular.js的处理,从而拥有以下重要而独特的性质:
l&所有表达式都在scope这个context里被执行,因此可以使用所有本地&$scope&中的变量。
l&如果一个表达式的执行导致类型错误或引用错误,这些错误将不会被抛出。
l&表达式里不允许任何控制函数流程的功能(如if/else等条件语句)
l&表达式可接受一个或多个串联起来的过滤器。
过滤器(filter)正如其名,作用就是接收一个输入,通过某个规则进行处理,然后返回处理后的结果。主要用在数据的格式化上,例如获取一个数组中的子集,对数组中的元素进行排序等。过滤器通常是伴随标记来使用的,将你model中的数据格式化为需要的格式。表单的控制功能主要涉及到数据验证以及表单控件的增强。ng内置了一些过滤器,它们是:
currency(货币)、date(日期)、filter(子串匹配)、json(格式化json对象)、limitTo(限制个数)、lowercase(小写)、uppercase(大写)、number(数字)、orderBy(排序)。
4.5.1过滤器使用方式
总共九种。除此之外还可以自定义过滤器,这个就强大了,可以满足任何要求的数据处理。Filter还是很简单的,需要明白的是内置的filter如何使用,以及自己如何定义一个filter。
filter的两种使用方法:
  1.&在模板中使用filter
  我们可以直接在{{}}中使用filter,跟在表达式后面用&|&分割,语法如下:
{{&expression&|&filter&}}&
也可以多个filter连用,上一个filter的输出将作为下一个filter的输入:
{{&expression&|&filter1&|&filter2&|&...&}}  
filter可以接收参数,参数用&:&进行分割,如下:
{{&expression&|&filter:argument1:argument2:...&}}  
除了对{{}}中的数据进行格式化,我们还可以在指令中使用filter,例如先对数组array进行过滤处理,然后再循环输出:
&span&ng-repeat="a&in&array&|&filter&"&  
2.&在controller和service中使用filter
  我们的js代码中也可以使用过滤器,方式就是我们熟悉的依赖注入,例如我要在controller中使用currency过滤器,只需将它注入到该controller中即可,代码如下:
app.controller('testC',function($scope,currencyFilter){
&&&&$scope.num&=&currencyFilter(123534);&&
在模板中使用{{num}}就可以直接输出$123,534.00了!在服务中使用filter也是同样的道理。
  如果你要在controller中使用多个filter,并不需要一个一个注入吗,ng提供了一个$filter服务可以来调用所需的filter,你只需注入一个$filter就够了,使用方法如下:
app.controller('testC',function($scope,$filter){
$scope.num&=&$filter('currency')(123534);  
$scope.date&=&$filter('date')(new&Date());&&
可以达到同样的效果。好处是你可以方便使用不同的filter了。
4.5.2&ng的内置过滤器
ng内置了九种过滤器,使用方法都非常简单,看文档即懂。不过为了以后不去翻它的文档,我在这里还是做一个详细的记录。
currency(货币)、date(日期)、filter(子串匹配)、json(格式化json对象)、limitTo(限制个数)、lowercase(小写)、uppercase(大写)、number(数字)、orderBy(排序)
1.&currency&(货币处理)
  使用currency可以将数字格式化为货币,默认是美元符号,你可以自己传入所需的符号,例如我传入人民币:
{{num&|&currency&:&'¥'}}  
2.&date&(日期格式化)
  原生的js对日期的格式化能力有限,ng提供的date过滤器基本可以满足一般的格式化要求。用法如下:
{{date&|&date&:&'yyyy-MM-dd&hh:mm:ss&EEEE'}}  
参数用来指定所要的格式,y&M&d&h&m&s&E&分别表示&年&月&日&时&分&秒&星期,你可以自由组合它们。也可以使用不同的个数来限制格式化的位数。另外参数也可以使用特定的描述性字符串,例如“shortTime”将会把时间格式为12:05&pm这样的。ng提供了八种描述性的字符串,个人觉得这些有点多余,我完全可以根据自己的意愿组合出想要的格式,不愿意去记这么多单词~
3.&filter(匹配子串)
  这个名叫filter的filter。用来处理一个数组,然后可以过滤出含有某个子串的元素,作为一个子数组来返回。可以是字符串数组,也可以是对象数组。如果是对象数组,可以匹配属性的值。它接收一个参数,用来定义子串的匹配规则。下面举个例子说明一下参数的用法,我用现在特别火的几个孩子定义了一个数组:
$scope.childrenArray&=&[
&&&&&&&&{name:'kimi',age:3},
&&&&&&&&{name:'cindy',age:4},
&&&&&&&&{name:'anglar',age:4},
&&&&&&&&{name:'shitou',age:6},
&&&&&&&&{name:'tiantian',age:5}
$scope.func&=&function(e){return&e.age&4;}{{&childrenArray&|&filter&:&'a'&}}&//匹配属性值中含有a的
{{&childrenArray&|&filter&:&4&}}&&//匹配属性值中含有4的
{{&childrenArray&|&filter&:&{name&:&'i'}&}}&//参数是对象,匹配name属性中含有i的
{{childrenArray&|&filter&:&func&}}&&//参数是函数,指定返回age&4的  
4.&json(格式化json对象)
  json过滤器可以把一个js对象格式化为json字符串,没有参数。这东西有什么用呢,我一般也不会在页面上输出一个json串啊,官网说它可以用来进行调试,嗯,是个不错的选择。或者,也可以用在js中使用,作用就和我们熟悉的JSON.stringify()一样。用法超级简单:
{{&jsonTest&|&json}}
5.&limitTo(限制数组长度或字符串长度)
  limitTo过滤器用来截取数组或字符串,接收一个参数用来指定截取的长度,如果参数是负值,则从数组尾部开始截取。个人觉得这个filter有点鸡肋,首先只能从数组或字符串的开头/尾部进行截取,其次,js原生的函数就可以代替它了,看看怎么用吧:
{{&childrenArray&|&limitTo&:&2&}}&&//将会显示数组中的前两项  
6.&lowercase(小写)
  把数据转化为全部小写。太简单了,不多解释。同样是很鸡肋的一个filter,没有参数,只能把整个字符串变为小写,不能指定字母。怎么用我都懒得写了。
7.&uppercase(大写)
  同上。
8.&number(格式化数字)
  number过滤器可以为一个数字加上千位分割,像这样,123,456,789。同时接收一个参数,可以指定float类型保留几位小数:
{{&num&|&number&:&2&}}  
9.&orderBy(排序)
  orderBy过滤器可以将一个数组中的元素进行排序,接收一个参数来指定排序规则,参数可以是一个字符串,表示以该属性名称进行排序。可以是一个函数,定义排序属性。还可以是一个数组,表示依次按数组中的属性值进行排序(若按第一项比较的值相等,再按第二项比较),还是拿上面的孩子数组举例:
&div&{{&childrenArray&|&orderBy&:&'age'&}}&/div&&&&&&&//按age属性值进行排序,若是-age,则倒序
&div&{{&childrenArray&|&orderBy&:&orderFunc&}}&/div&&&&//按照函数的返回值进行排序
&div&{{&childrenArray&|&orderBy&:&['age','name']&}}&/div&&&//如果age相同,按照name进行排序  内置的过滤器介绍完了,写的我都快睡着了。。。正如你所看到的,ng内置的过滤器也并不是万能的,事实上好多都比较鸡肋。更个性化的需求就需要我们来定义自己的过滤器了,下面来看看如何自定义过滤器。
4.5.3自定义过滤器及示例
  filter的自定义方式也很简单,使用module的filter方法,返回一个函数,该函数接收
输入值,并返回处理后的结果。话不多说,我们来写一个看看。比如我需要一个过滤器,它可以返回一个数组中下标为奇数的元素,代码如下:
app.filter('odditems',function(){
&&&&return&function(inputArray){
&&&&&&&&var&array&=&[];
&&&&&&&&for(var&i=0;i&inputArray.i++){
&&&&&&&&&&&&if(i%2!==0){
&&&&&&&&&&&&&&&&array.push(inputArray[i]);
&&&&&&&&&&&&}
&&&&&&&&return&
格式就是这样,你的处理逻辑就写在内部的那个闭包函数中。你也可以让自己的过滤器接收参数,参数就定义在return的那个函数中,作为第二个参数,或者更多个参数也可以。
自定义过滤器实例(例04):
/*&View&html&*/
First&name:&input&ng-model="user.firstName"/&&br/&
Last&&name:&input&ng-model="user.lastName"/&&&br/&
First&name:{{user.firstName}}&&&&&&Last&&name:{{user.lastName}}&&br/&
Fullname:{{user&|&flFullname}}&br/&
Fullname:{{user&|&flFullname:"-"}}&br/&
Fullname:{{user&|&flFullname:"o"&|&uppercase&}}
/*&Controller&js&*/
demoApp.filter("flFullname",&function()&{
&&&&return&function(user,&sep)&{
&&&&&&&&sep&=&sep&||&"&";
&&&&&&&&user&=&user&||&{};
&&&&&&&&fullName&=&"";
&&&&&&&&if(user.firstName){fullName&+=&user.firstN}
&&&&&&&&if(user.lastName){fullName&=&fullName&+&sep&+&user.lastN}
&&&&&&&&if(fullName&&&&fullName.length&0){return&fullN
&&&&&&&&}else{return&"";}
4.6指令(directive)
  通过使用模板,我们可以把model和controller中的数据组装起来呈现给浏览器,还可以通过数据绑定,实时更新视图,让我们的页面变成动态的。
  模板中可以使用的东西包括以下四种:
1.指令(directive):ng提供的或者自定义的标签和属性,用来增强HTML表现力;
2.标记(markup):即双大括号{{}},可将数据单向绑定到HTML中;
3.过滤器(filter):用来格式化输出数据;
4.表单控制:用来增强表单的验证功能。
其中,指令无疑是使用量最大的,ng内置了很多指令用来控制模板,如ng-repeat,ng-class,也有很多指令来帮你完成业务逻辑,如ng-controller,ng-model。
指令的几种使用方式如下:
l&作为标签:&my-dir&&/my-dir&
l&作为属性:&span&my-dir="exp"&&/span&
l&作为注释:&!--&directive:&my-dir&exp&--&
l&作为类名:&span&class="my-dir:&"&&/span&
其实常用的就是作为标签和属性。
4.6.1样式相关的指令
  既然模板就是普通的HTML,那我首要关心的就是样式的控制,元素的定位、字体、背景色等等如何可以灵活控制。下面来看看常用的样式控制指令。
1.&ng-class
   ng-class用来给元素绑定类名,其表达式的返回值可以是以下三种:
l&类名字符串,可以用空格分割多个类名,如’redtext&boldtext’;
l&类名数组,数组中的每一项都会层叠起来生效;
l&一个名值对应的map,其键值为类名,值为boolean类型,当值为true时,该类会被加在元素上。
  下面来看一个使用map的例子:
ng-class测试
红色&加粗&删除线&
map:{redtext:{{red}},&boldtext:{{bold}},&striketext:{{strike}}}
  如果你想拼接一个类名出来,可以使用插值表达式,如:
  &div&class=”{{style}}text”&字体样式测试&/div&
  然后在controller中指定style的值:
  $scope.style&=&‘red’;
  注意我用了class而不是ng-class,这是不可以对换的,官方的文档也未做说明,姑且认为这是ng的语法规则吧。
  与ng-class相近的,ng还提供了ng-class-odd、ng-class-even两个指令,用来配合ng-repeat分别在奇数列和偶数列使用对应的类。这个用来在表格中实现隔行换色再方便不过了。
2.&ng-style
  ng-style用来绑定元素的css样式,其表达式的返回值为一个js对象,键为css样式名,值为该样式对应的合法取值。用法比较简单:
&div&ng-style="{color:'red'}"&ng-style测试&/div&
&div&ng-style="style"&ng-style测试&/div&
$scope.style&=&{color:'red'};  
3.&ng-show,ng-hide
   对于比较常用的元素显隐控制,ng也做了封装,ng-show和ng-hide的值为boolean类型的表达式,当值为true时,对应的show或hide生效。框架会用display:block和display:none来控制元素的显隐。
4.6.2表单控件功能相关指令
  对于常用的表单控件功能,ng也做了封装,方便灵活控制。
  ng-checked控制radio和checkbox的选中状态
  ng-selected控制下拉框的选中状态
  ng-disabled控制失效状态
  ng-multiple控制多选
  ng-readonly控制只读状态
  以上指令的取值均为boolean类型,当值为true时相关状态生效,道理比较简单就不多做解释。注意:&上面的这些只是单向绑定,即只是从数据到模板,不能反作用于数据。要双向绑定,还是要使用&ng-model&。
4.6.3事件绑定相关指令
事件绑定是javascrpt中比较重要的一部分内容,ng对此也做了详细的封装,正如我们之前使用过的ng-click一样,事件的指令如下:
  ng-change
  ng-dblclick
  ng-mousedown
  ng-mouseenter
  ng-mouseleave
  ng-mousemove
  ng-mouseover
  ng-mouseup
  ng-submit
  事件绑定指令的取值为函数,并且需要加上括号,例如:
&select&ng-change=”change($event)”&&/select&  
然后在controller中定义如下:
$scope.change&=&function($event){
&&&&&&&&&alert($event.target);
&&&&&&&&&//……………………
在模板中可以用变量$event将事件对象传递到controller中。
对于ng的这种设计,一些人有所质疑,视图与事件绑定混在一起到底好不好?我们不是要讲究视图与逻辑分离吗?如此一来,把事件的绑定又变回了内联的,岂不是历史的倒退。我也一样对此表示不解,因为不写onclick已经很多年。。。但既然已经存在了,我们不妨往合理的方向上想一想,或许ng的设计者压根就不想让模板成为单纯的视图层,本来就是想增强HTML,让它有一点业务能力。这么想的话似乎也能想通,好吧,先欺骗一下自己吧~
4.6.4特殊的ng-src和ng-href
在说明这两个指令的特殊之前,需要先了解一下ng的启动及执行过程,如下图:
1)&浏览器加载静态HTML文件并解析为DOM;
  2)&浏览器加载angular.js文件;
  3)&angular监听DOMContentLoaded&事件,监听到时开始启动;
  4)&angular寻找ng-app指令,确定作用范围;
  5)&找到app中定义的Module使用$injector服务进行依赖注入;
  6)&根据$injector服务创建$compile服务用于编译;
  7)&$compile服务编译DOM中的指令、过滤器等;
  8)&使用ng-init指令,将作用域中的变量进行替换;
  9)&最后生成了我们在最终视图。
  可以看到,ng框架是在DOMcontent加载完毕后才开始发挥作用。假如我们模板中有一张图片如下:
  &img&src="http://m.cnblogs.com/142260/”{{imgUrl}}”&/&
  那么在页面开始加载到ng编译完成之前,页面上会一直显示一张错误的图片,因为路径{{imgUrl}}还未被替换。
  为了避免这种情况,我们使用ng-src指令,这样在路径被正确得到之前就不会显示找不到图片。同理,&a&标签的href属性也需要换成ng-href,这样页面上就不会先出现一个地址错误的链接。
顺着这个思路再多想一点,我们在模板中使用{{}}显示数据时,在ng编译完成之前页面上岂不是会显示出大括号及里面的表达式?确实是这样。为了避免这个,ng中有一个与{{}}等同的指令:ng-bind,同样用于单向绑定,在页面刚加载的时候就不会显示出对用户无用的数据了。尽管这样你可能不但没舒心反而更纠结了,{{}}那么好用易理解,还不能用了不成?好消息是我们依然可以使用。因为我编写的是单页面应用,页面只会在加载index.html的时
候出这个问题,只需在index.html中的模板中换成ng-bind就行。其他的模板是我们动态加载的,就可以放心使用{{}}了。
4.6.5&自定义指令示例
下面我们来解析下指令的例子(例07)。
1.首先,我们定义一个名为userInfo的指令:
demoApp.directive('userInfo',function(){
&&&&&&&&restrict&:&'E',
&&&&&&&&templateUrl&:&'userInfoTemplate.html',
&&&&&&&&replace&:&true,
&&&&&&&&transclude&:&true,
&&&&&&&&scope&:&{
&&&&&&&&&&&&mytitle&:&'=etitle'
&&&&&&&&},
&&&&&&&&link&:&function(scope,element,attrs){
&&&&&&&&&&&&scope.showText&=&
&&&&&&&&&&&&scope.toggleText&=&function(){
&&&&&&&&&&&&&&&&scope.showText&=&!&scope.showT
&&&&&&&&&&&&}
Restrict为'E':用作标签;replace为true:用模板替换当前标签;transclude为true:将当前元素的内容转移到模板中;scope&为&{mytitle&:&'=etitle'}:定义一个名为mytitle的MODEL,其值指向当前元素的etitle属性;templateUrl为'userInfoTemplate.html':模板内容为ng-template定义ID为userInfoTemplate.html的内容;link:指定所包含的行为。其具体的说明及其他参数,请参考:6.2指令详解。
2.&userInfoTemplate.html模板为:
&script&type="text/ng-template"&id="userInfoTemplate.html"&
&div&class="mybox"&
&div&class="mytitle"&style="cursor:&"&ng-click="toggleText()"&
{&{mytitle}&}
&div&ng-transclude&ng-show="showText"&
将当前元素的内容添加到有ng-transclude属性的这个DIV下,默认是隐藏的。
3.Controller信息:
demoApp.controller("test7Controller",&function($scope){
$scope.title&=&'个人简介';
$scope.text&=&'大家好,我正在研究AngularJs,欢迎大家与我交流。';
$scope.updateInfo&=&function&(){
$scope.title&=&'个人信息';
$scope.text&=&'大家好,今天天气真好!';
4.指令使用方式(View信息)为:
&user-info&etitle="title"&{&{text}&}&/user-info&
Etitle指向Controller中的$scope.title。注意命名方式:指令名为userInfo,对应的标签为user-info。
4.7服务(service)
4.7.1服务介绍
  服务这个概念其实并不陌生,在其他语言中如便有这样的概念,其作用就是对外提供某个特定的功能,如消息服务,文件压缩服务等,是一个独立的模块。ng的服务是这样定义的:
Angular&services&are&singletons&objects&or&functions&that&carry&out&specific&tasks&common&to&web&apps.
它是一个单例对象或函数,对外提供特定的功能。
首先是一个单例,即无论这个服务被注入到任何地方,对象始终只有一个实例。
其次这与我们自己定义一个function然后在其他地方调用不同,因为服务被定义在一个模块中,所以其使用范围是可以被我们管理的。ng的避免全局变量污染意识非常强。
  ng提供了很多内置的服务,可以到API中查看http://docs.angularjs.org/api/。知道了概念,我们来拉一个service出来溜溜,看看到底是个什么用法。  
  我们在controller中直接声明$location服务,这依靠ng的依赖注入机制。$location提供地址栏相关的服务,我们在此只是简单的获取当前的地址。
  服务的使用是如此简单,我们可以把服务注入到controller、指令或者是其他服务中。
4.7.2自定义服务
  如同指令一样,系统内置的服务以$开头,我们也可以自己定义一个服务。定义服务的方式有如下几种:
l&使用系统内置的$provide服务;
l&使用Module的factory方法;
l&使用Module的service方法。
  下面通过一个小例子来分别试验一下。我们定义一个名为remoteData服务,它可以从远程获取数据,这也是我们在程序中经常使用的功能。不过我这里没有远程服务器,就写死一点数据模拟一下。
//使用$provide来定义
var&app&=&angular.module('MyApp',&[],&function($provide)&{
&&&&$provide.factory('remoteData',&function()&{
&var&data&=&{name:'n',value:'v'};
&&&&&&&&return&
//使用factory方法
app.factory('remoteData',function(){
&&&&var&data&=&{name:'n',value:'v'};
&&&&return&
//使用service方法
app.service('remoteData',function(){
&&&&this.name&=&'n';
&&&&this.value&=&'v';
Module的factory和$provide的factory方法是一模一样的,从官网文档看它们其实就是一回事。至于Module内部是如何调用的,我此处并不打算深究,我只要知道怎么用就好了。
再看Module的service方法,它没有return任何东西,是因为service方法本身返回一个构造器,系统会自动使用new关键字来创建出一个对象。所以我们看到在构造器函数内可以使用this,这样调用该服务的地方便可以直接通过remoteData.name来访问数据了。
4.7.3管理服务的依赖关系
  服务与服务中间可以有依赖关系,例如我们这里定义一个名为validate的服务,它的作用是验证数据是否合法,它需要依赖我们从远程获取数据的服务remoteData。代码如下:
& &在factory的参数中,我们可以直接传入服务remoteData,ng的依赖注入机制便帮我们做好了其他工作。不过一定要保证这个参数的名称与服务名称一致,ng是根据名称来识别的。若参数的名次与服务名称不一致,你就必须显示的声明一下,方式如下:
app.factory('validate',['remoteData',function(remoteDataService){
&&&&return&function(){
&&&&&&&&if(remoteDataService.name=='n'){
&&&&&&&&&&&&alert('验证通过');
我们在controller中注入服务也是同样的道理,使用的名称需要与服务名称一致才可以正确注入。否则,你必须使用$inject来手动指定注入的服务。比如:
function&testC(scope,rd){
&&&&scope.getData&=&function(){
&&&&&&&&alert('name:'+rd.name+'&&&value:'+rd.value);
testC.$inject&=&['$scope','remoteData'];
  在controller中注入服务,也可以在定义controller时使用数组作为第二个参数,在此处
把服务注入进去,这样在函数体中使用不一致的服务名称也是可以的,不过要确保注入的顺序是一致的,如:
app.controller('testC',['$scope','remoteData',function($scope,rd){
&&&&$scope.getData&=&function(){
&&&&&&&&alert('name:'+rd.name+'&&&value:'+rd.value);
4.7.4&自定义服务示例
接下来让我们看下例子(例08&自定义服务)代码,自定义userService服务:
demoApp.factory('userService',&['$http',&function($http)&{
var&doGetUser&=&function(userId,&path)&{
//return&$http({
//method:&'JSONP',
//url:&path
/*手动指定数据*/
var&data&=&{userId:"woshishui",userName:"我是谁",userInfo:"我是谁!我是谁!"};;
if(userId=='zhangsan'){
data&=&{userId:"zhangsan",userName:"张三",userInfo:"我是张三,我为自己"};
}else&if(userId=='lisi'){
data&=&{userId:"lisi",userName:"李四",userInfo:"我是李四,我为卿狂!"};
/*userService对外暴露的函数,可有多个*/
getUser:&function(userId)&{&
return&doGetUser(userId,&'../xxx/xxx.action');&
我们创建了一个只有一个方法的userService,getUser为这个服务从后台获取用户信息的函数,并且对外暴露。当然,由于这是一个静态的例子,无法访问后台,那么我们便制定其返回的数据。
然后我们把这个服务添加到我们的controller中。我们建立一个controller并加载(或者注入)userService作为运行时依赖,我们把service的名字作为参数传递给controller&函数:
demoApp.controller("test8Controller",&function($scope,userService){
/*文章信息*/
$scope.articles&=&[{
title&:&"爱飞像风",
userId&:&"zhangsan",
userName&:&"张三"
title&:&"无法停止的雨",
userId&:&"lisi",
userName&:&"李四"
$scope.showUserInfo&=&//显示作者详细信息开关
$scope.currentUser&=&{};&//当前选中的作者
$scope.getUserInfo&=&function(userId){
$scope.currentUser&=&userService.getUser(userId);
//调用&userService的getUser函数
$scope.showUserInfo&=&
setTimeout(function(){//定时器:隐藏作者详细信息
$scope.showUserInfo&=&
我们的userService注入到我们的test8Controller后,我们就可以像使用其他服务(我们前面提到的$http服务)一样的使用userService了。
相关的HTML代码如下:
/*&View&HTML*/
&tr&ng-repeat="article_&in&articles"&
{{article_.title}}
&a&href="javascript:void(0);" target="_blank" rel="nofollow"&
&div&ng-show="showUserInfo"&
用户ID:{{currentUser.userId}}&br/&
用户名:{{currentUser.userName}}&br/&
用户简介:{{currentUser.userInfo}}&br/&
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&=&questionM
&&&&$scope.nowTime&=&new&Date().valueOf();
&&&&$scope.templates&=&&//赋值到$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事件来进行视图切换,另一个方法是用的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页面,代码如下:
&h3&Route&:&List.html(用户列表页面)&/h3&&&
&li&ng-repeat="user&in&users"&&&
&&&&& &a&href="http://m.cnblogs.com/7063.html?full=1#/list/{{&user.userId&}}" target="_blank" rel="nofollow"&
&h3&Route&:&detail.html(用户详细信息页面)&/h3&&&
&h3&用户名:&span&style="color:&"&{{userDetail.userName}}&/span&&/h3&
&span&用户ID:{{userDetail.userId}}&/span&&span&用户名:{{userDetail.userName}}&/span&
用户简介:&span&{{userDetail.userInfo}}&/span&
&a&href="http://m.cnblogs.com/7063.html?full=1#/list" target="_blank" rel="nofollow"&返回&/a&&&
4.&路由局部刷新位置:
&h1&AngularJS路由(Route)&示例&/h1&&&
&div&ng-view&&/div&
4.10&NG动画效果
4.10.1&NG动画效果简介
NG动画效果,现在可以通过或者是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()&{
& &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(){&
beforeAddClass&:&function&(element,&className,&done)&{&
$(element).stop().animate({
'border-width':1
},2000,&function()&{
removeClass&:&function&(element&,className&,done&)&{&
$(element).stop().animate({
'border-width':50
},3000,&function()&{
动画效果的含义就是:在匹配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&=&
5&功能演示
略(详情请看AngularJS/demo&WEB演示)
6&AngularJS进阶
6.1数据绑定原理研究
Angular用户都想知道数据绑定是怎么实现的。你可能会看到各种各样的词汇:$watch、$apply、$digest、dirty-checking...它们是什么?它们是如何工作的呢?这里我想回答这些问题,其实它们在官方的文档里都已经回答了,但是我还是想把它们结合在一起来讲,但是我只是用一种简单的方法来讲解,如果要想了解技术细节,查看源代码。
6.1.1&AngularJS扩展事件循环
我们的浏览器一直在等待事件,比如用户交互。假如你点击一个按钮或者在输入框里输入东西,事件的回调函数就会在javascript解释器里执行,然后你就可以做任何DOM操作,等回调函数执行完毕时,浏览器就会相应地对DOM做出变化。(记住,这是个重要的概念),为了解释什么是context以及它如何工作,我们还需要解释更多的概念。
6.1.2&$watch&队列
每次你绑定一些东西到你的DOM上时你就会往$watch队列里插入一条$watch。想象一下$watch就是那个可以检测它监视的model里时候有变化的东西。例如你有如下的代码:
/*View&&index.html&*/
User:&&input&type="text"&ng-model="user"&/&
Password:&&input&type="password"&ng-model="pass"&/&
在这里我们有个$scope.user,他被绑定在了第一个输入框上,还有个$scope.pass,它被绑定在了第二个输入框上,然后我们在$watch&list里面加入两个$watch。
再看下面的例子:
/*Controller&&controllers.js&*/
app.controller('MainCtrl',&function($scope)&{
&& $scope.foo&=&"Foo";
&& $scope.world&=&"World";
/*View&&index.html&*/
Hello,&{{&World&}}
这里,即便我们在$scope上添加了两个东西,但是只有一个绑定在了DOM上,因此在这里只生成了一个$watch。
再看下面的例子:
/*Controller&&controllers.js&*/
app.controller('MainCtrl',&function($scope)&{
&&$scope.people&=&[...];
/*View&&index.html&*/
&&&li&ng-repeat="person&in&people"&
&&&&&&{{person.name}}&-&{{person.age}}
这里又生成了多少个$watch呢?每个person有两个(一个name,一个age),然后ng-repeat又有一个,因此10个person一共是(2&*&10)&+1,也就是说有21个$watch。&
因此,每一个绑定到了DOM上的数据都会生成一个$watch。
那这写$watch是什么时候生成的呢?&
当我们的模版加载完毕时,也就是在linking阶段(Angular分为compile阶段和linking阶段),Angular解释器会寻找每个directive,然后生成每个需要的$watch。
6.1.3&$digest循环
还记得我前面提到的扩展的事件循环吗?当浏览器接收到可以被angular&context处理的事件时,$digest循环就会触发。这个循环是由两个更小的循环组合起来的。一个处理evalAsync队列,另一个处理$watch队列。&这个是处理什么的呢?$digest将会遍历我们的$watch,然后询问:
o嘿,$watch,你的值是什么?&
o好的,它改变过吗?&
o没有,先生。
o(这个变量没变过,那下一个)
o你呢,你的值是多少?&
o报告,是Foo。
o刚才改变过没?&
o改变过,刚才是Bar。
o(很好,我们有DOM需要更新了)
o继续询问直到$watch队列都检查过。
这就是所谓的dirty-checking。既然所有的$watch都检查完了,那就要问了:有没有$watch更新过?如果有至少一个更新过,这个循环就会再次触发,直到所有的$watch都没有变化。这样就能够保证每个model都已经不会再变化。记住如果循环超过10次的话,它将会抛出一个异常,防止无限循环。当$digest循环结束时,DOM相应地变化。
/*Controller&&controllers.js&*/
app.controller('MainCtrl',&function()&{
&&$scope.name&=&"Foo";
&&$scope.changeFoo&=&function()&{
&&&&&&$scope.name&=&"Bar";
/*View&&index.html&*/
{{&name&}}
&button&ng-click="changeFoo()"&Change&the&name&/button&
这里我们有一个$watch因为ng-click不生成$watch(函数是不会变的)。
我们可以看出ng的处理流程:
o我们按下按钮;
o浏览器接收到一个事件,进入angular&context;
o$digest循环开始执行,查询每个$watch是否变化;
o由于监视$scope.name的$watch报告了变化,它会强制再执行一次$digest循环;
o新的$digest循环没有检测到变化;
o浏览器拿回控制权,更新与$scope.name新值相应部分的DOM。
这里很重要的是每一个进入angular&context的事件都会执行一个$digest循环,也就是说每次我们输入一个字母循环都会检查整个页面的所有$watch。
6.1.4如何进入angular&context
谁决定什么事件进入angular&context,而哪些又不进入呢?通过$apply!
如果当事件触发时,你调用$apply,它会进入angular&context,如果没有调用就不会进入。现在你可能会问:刚才的例子里我也没有调用$apply啊,为什么?Angular已经做了!因此你点击带有ng-click的元素时,时间就会被封装到一个$apply调用。如果你有一个ng-model="foo"的输入框,然后你敲一个f,事件就会这样调用$apply("foo&=&'f';")。
Angular什么时候不会自动为我们$apply呢?
这是Angular新手共同的痛处。为什么我的jQuery不会更新我绑定的东西呢?因为jQuery没有调用$apply,事件没有进入angular&context,$digest循环永远没有执行。
我们来看一个有趣的例子:
假设我们有下面这个directive和controller。
/*Controller&&app.js&*/
app.directive('clickable',&function()&{
&&restrict:&"E",
&&scope:&{
&&&&foo:&'=',
&&&&bar:&'='
&&template:&'&ul&style="&li&{{foo}}&/li&&li&{{bar}}&/li&&/ul&',
&&link:&function(scope,&element,&attrs)&{
&&&&element.bind('click',&function()&{
&&&&&&scope.foo++;
&&&&&&scope.bar++;
app.controller('MainCtrl',&function($scope)&{
&&$scope.foo&=&0;
&&$scope.bar&=&0;
它将foo和bar从controller里绑定到一个list里面,每次点击这个元素的时候,foo和bar都会自增1。那我们点击元素的时候会发生什么呢?我们能看到更新吗?答案是否定的。因为点击事件是一个没有封装到$apply里面的常见的事件,这意味着我们会失去我们的计数吗?不会。
真正的结果是:$scope确实改变了,但是没有强制$digest循环,监视foo&和bar的$watch没有执行。也就是说如果我们自己执行一次$apply那么这些$watch就会看见这些变化,然后根据需要更新DOM。
执行$apply:
element.bind('click',&function()&{
scope.foo++;
&&scope.bar++;
&&scope.$apply();
$apply是我们的$scope(或者是direcvie里的link函数中的scope)的一个函数,调用它会强制一次$digest循环(除非当前正在执行循环,这种情况下会抛出一个异常,这是我们不需要在那里执行$apply的标志)。
更好的使用$apply的方法:
element.bind('click',&function()&{
&&scope.$apply(function()&{
&&&&&&scope.foo++;
&&&&&&scope.bar++;
有什么不一样的?差别就是在第一个版本中,我们是在angular&context的外面更新的数据,如果有发生错误,Angular永远不知道。很明显在这个像个小玩具的例子里面不会出什么大错,但是想象一下我们如果有个alert框显示错误给用户,然后我们有个第三方的库进行一个网络调用然后失败了,如果我们不把它封装进$apply里面,Angular永远不会知道失败了,alert框就永远不会弹出来了。
因此,如果你想使用一个jQuery插件,并且要执行$digest循环来更新你的DOM的话,要确保你调用了$apply。
有时候我想多说一句的是有些人在不得不调用$apply时会“感觉不妙”,因为他们会觉得他们做错了什么。其实不是这样的,Angular不是什么魔术师,他也不知道第三方库想要更新绑定的数据。
6.1.5使用$watch来监视
你已经知道了我们设置的任何绑定都有一个它自己的$watch,当需要时更新DOM,但是我们如果要自定义自己的watches呢?简单,来看个例子:
/*Controller&&app.js&*/
app.controller('MainCtrl',&function($scope)&{
&&$scope.name&=&"Angular";
&&$scope.updated&=&-1;
&&$scope.$watch('name',&function()&{
&&&&$scope.updated++;
/*View&&index.html*/
&body&ng-controller="MainCtrl"&
&&&input&ng-model="name"&/&
&&Name&updated:&{{updated}}&times.
这就是我们创造一个新的$watch的方法。第一个参数是一个字符串或者函数,在这里是只是一个字符串,就是我们要监视的变量的名字,在这里,$scope.name(注意我们只需要
用name)。第二个参数是当$watch说我监视的表达式发生变化后要执行的。我们要知道的第一件事就是当controller执行到这个$watch时,它会立即执行一次,因此我们设置updated为-1。
/*Controller&&app.js&*/
app.controller('MainCtrl',&function($scope)&{
&&$scope.name&=&"Angular";
&&$scope.updated&=&0;
&&$scope.$watch('name',&function(newValue,&oldValue)&{
&&&&if&(newValue&===&oldValue)&{&&}&//&AKA&first&run
&&&&$scope.updated++;
/*View&&index.html*/
&body&ng-controller="MainCtrl"&
&&&input&ng-model="name"&/&
&&Name&updated:&{{updated}}&times.
watch的第二个参数接受两个参数,新值和旧值。我

我要回帖

更多关于 angularjs ajax 例子 的文章

 

随机推荐