AngularJS入门教程(二):AngularJS模板


Posted in Javascript onDecember 06, 2014

是时候给这些网页来点动态特性了——用AngularJS!我们这里为后面要加入的控制器添加了一个测试。

一个应用的代码架构有很多种。对于AngularJS应用,我们鼓励使用模型-视图-控制器(MVC)模式解耦代码和分离关注点。考虑到这一点,我们用AngularJS来为我们的应用添加一些模型、视图和控制器。

请重置工作目录:

git checkout -f step-2

我们的应用现在有了一个包含三部手机的列表。

步骤1和步骤2之间最重要的不同在下面列出。你可以到GitHub去看完整的差别。

视图和模板

在AngularJS中,一个视图是模型通过HTML**模板**渲染之后的映射。这意味着,不论模型什么时候发生变化,AngularJS会实时更新结合点,随之更新视图。

比如,视图组件被AngularJS用下面这个模板构建出来:

<html ng-app>

<head>

  ...

  <script src="lib/angular/angular.js"></script>

  <script src="js/controllers.js"></script>

</head>

<body ng-controller="PhoneListCtrl">
  <ul>

    <li ng-repeat="phone in phones">

      {{phone.name}}

    <p>{{phone.snippet}}</p>

    </li>

  </ul>

</body>

</html>

我们刚刚把静态编码的手机列表替换掉了,因为这里我们使用ngRepeat指令和两个用花括号包裹起来的AngularJS表达式——{{phone.name}}和{{phone.snippet}}——能达到同样的效果。

1.在<li>标签里面的ng-repeat="phone in phones"语句是一个AngularJS迭代器。这个迭代器告诉AngularJS用第一个<li>标签作为模板为列表中的每一部手机创建一个<li>元素。

2.正如我们在第0步时学到的,包裹在phone.name和phone.snippet周围的花括号标识着数据绑定。和常量计算不同的是,这里的表达式实际上是我们应用的一个数据模型引用,这些我们在PhoneListCtrl控制器里面都设置好了。

模型和控制器

在PhoneListCtrl控制器里面初始化了数据模型(这里只不过是一个包含了数组的函数,数组中存储的对象是手机数据列表):

app/js/controller.js:

function PhoneListCtrl($scope) {

  $scope.phones = [

    {"name": "Nexus S",

     "snippet": "Fast just got faster with Nexus S."},

    {"name": "Motorola XOOM™ with Wi-Fi",

     "snippet": "The Next, Next Generation tablet."},

    {"name": "MOTOROLA XOOM™",

     "snippet": "The Next, Next Generation tablet."}

  ];

}

尽管控制器看起来并没有起到什么控制的作用,但是它在这里起到了至关重要的作用。通过给定我们数据模型的语境,控制器允许我们建立模型和视图之间的数据绑定。我们是这样把表现层,数据和逻辑部件联系在一起的:

1.PhoneListCtrl——控制器方法的名字(在JS文件controllers.js中)和<body>标签里面的ngController指令的值相匹配。

2.手机的数据此时与注入到我们控制器函数的作用域($scope)相关联。当应用启动之后,会有一个根作用域被创建出来,而控制器的作用域是根作用域的一个典型后继。这个控制器的作用域对所有<body ng-controller="PhoneListCtrl">标记内部的数据绑定有效。

AngularJS的作用域理论非常重要:一个作用域可以视作模板、模型和控制器协同工作的粘接器。AngularJS使用作用域,同时还有模板中的信息,数据模型和控制器。这些可以帮助模型和视图分离,但是他们两者确实是同步的!任何对于模型的更改都会即时反映在视图上;任何在视图上的更改都会被立刻体现在模型中。

想要更加深入理解AngularJS的作用域,请参看AngularJS作用域文档。

测试

“AngularJS方式”让开发时代码测试变得十分简单。让我们来瞅一眼下面这个为控制器新添加的单元测试:

test/unit/controllersSpec.js:

describe('PhoneCat controllers', function() {
  describe('PhoneListCtrl', function(){
    it('should create "phones" model with 3 phones', function() {

      var scope = {},

      ctrl = new PhoneListCtrl(scope);
      expect(scope.phones.length).toBe(3);

    });

  });

});

这个测试验证了我们的手机数组里面有三条记录(暂时无需弄明白这个测试脚本)。这个例子显示出为AngularJS的代码创建一个单元测试是多么的容易。正因为测试在软件开发中是必不可少的环节,所以我们使得在AngularJS可以轻易地构建测试,来鼓励开发者多写它们。

在写测试的时候,AngularJS的开发者倾向于使用Jasmine行为驱动开发(BBD)框架中的语法。尽管AngularJS没有强迫你使用Jasmine,但是我们在教程里面所有的测试都使用Jasmine编写。你可以在Jasmine的官方主页或者Jasmine Wiki上获得相关知识。

基于AngularJS的项目被预先配置为使用JsTestDriver来运行单元测试。

你可以像下面这样运行测试:

1.在一个单独的终端上,进入到angular-phonecat目录并且运行./scripts/test-server.sh来启动测试(Windows命令行下请输入.\scripts\test-server.bat来运行脚本,后面脚本命令运行方式类似);
2.打开一个新的浏览器窗口,并且转到http://localhost:9876 ;
3.选择“Capture this browser in strict mode”。

这个时候,你可以抛开你的窗口不管然后把这事忘了。JsTestDriver会自己把测试跑完并且把结果输出在你的终端里。

4.运行./scripts/test.sh进行测试 。

你应当看到类似于如下的结果:

Chrome: Runner reset.

.

Total 1 tests (Passed: 1; Fails: 0; Errors: 0) (2.00 ms)

  Chrome 19.0.1084.36 Mac OS: Run 1 tests (Passed: 1; Fails: 0; Errors 0) (2.00 ms)

耶!测试通过了!或者没有... 注意:如果在你运行测试之后发生了错误,关闭浏览器然后回到终端关了脚本,然后在重新来一边上面的步骤。

练习

为index.html添加另一个数据绑定。例如:

<p>Total number of phones: {{phones.length}}</p>

创建一个新的数据模型属性,并且把它绑定到模板上。例如:
$scope.hello = "Hello, World!"

更新你的浏览器,确保显示出来“Hello, World!”

用一个迭代器创建一个简单的表:

<table>

    <tr><th>row number</th></tr>

    <tr ng-repeat="i in [0, 1, 2, 3, 4, 5, 6, 7]"><td>{{i}}</td></tr>

</table>

现在让数据模型表达式的i增加1:
<table>

    <tr><th>row number</th></tr>

    <tr ng-repeat="i in [0, 1, 2, 3, 4, 5, 6, 7]"><td>{{i+1}}</td></tr>

</table>

确定把toBe(3)改成toBe(4)之后单元测试失败,然后重新跑一遍./scripts/test.sh脚本

总结

你现在拥有一个模型,视图,控制器分离的动态应用了,并且你随时进行了测试。现在,你可以进入到步骤3来为应用加入全文检索功能了。

Javascript 相关文章推荐
Javascript实现仿WebQQ界面的“浮云”兼容 IE7以上版本及FF
Apr 27 Javascript
Javascript的数组与字典用法与遍历对象的属性技巧
Nov 07 Javascript
浅析Js中的单引号与双引号问题
Nov 06 Javascript
jQuery操作input值的各种方法总结
Nov 21 Javascript
Node.js编码规范
Jul 14 Javascript
使用Chrome调试JavaScript的断点设置和调试技巧
Dec 16 Javascript
prototype框架中美元符号$用法分析
Jan 22 Javascript
为什么JavaScript没有块级作用域
May 22 Javascript
JavaScript获取当前url根目录(路径)
Jun 17 Javascript
jQuery EasyUI 折叠面板accordion的使用实例(分享)
Dec 25 jQuery
基于vue、react实现倒计时效果
Aug 26 Javascript
vue使用wavesurfer.js解决音频可视化播放问题
Apr 04 Vue.js
AngularJS入门教程(一):静态模板
Dec 06 #Javascript
AngularJS入门教程(零):引导程序
Dec 06 #Javascript
AngularJS入门教程之学习环境搭建
Dec 06 #Javascript
AngularJS入门教程之Hello World!
Dec 06 #Javascript
JavaScript中的Web worker多线程API研究
Dec 06 #Javascript
JavaScript实现的一个日期格式化函数分享
Dec 06 #Javascript
JavaScript实现twitter puddles算法实例
Dec 06 #Javascript
You might like
PHP中创建并处理图象
2006/10/09 PHP
一个程序下载的管理程序(四)
2006/10/09 PHP
PHP表单验证的3个函数ISSET()、empty()、is_numeric()的使用方法
2011/08/22 PHP
让ThinkPHP的模板引擎达到最佳效率的方法详解
2017/03/14 PHP
给Function做的OOP扩展
2009/05/07 Javascript
Javascript学习笔记6 prototype的提出
2010/01/11 Javascript
Jquery replace 字符替换实现代码
2010/12/02 Javascript
JavaScript 处理Iframe自适应高度(同或不同域名下)
2013/03/29 Javascript
Jqgrid设置全选(选择)及获取选择行的值示例代码
2013/12/28 Javascript
Javascript 拖拽雏形(逐行分析代码,让你轻松了拖拽的原理)
2015/01/23 Javascript
JS+CSS实现Li列表隔行换色效果的方法
2015/02/16 Javascript
jQuery中bind(),live(),delegate(),on()绑定事件方法实例详解
2016/01/19 Javascript
js判断数组key是否存在(不用循环)的简单实例
2016/08/03 Javascript
jQuery插件echarts实现的多柱子柱状图效果示例【附demo源码下载】
2017/03/04 Javascript
JS 插件dropload下拉刷新、上拉加载使用小结
2017/04/13 Javascript
详解Vue 方法与事件处理器
2017/06/20 Javascript
微信小程序之页面拦截器的示例代码
2017/09/07 Javascript
原生JS实现移动端web轮播图详解(结合Tween算法造轮子)
2017/09/10 Javascript
vue.js整合vux中的上拉加载下拉刷新实例教程
2018/01/09 Javascript
详解React-Router中Url参数改变页面不刷新的解决办法
2018/05/08 Javascript
mpvue将vue项目转换为小程序
2018/09/30 Javascript
JS中的一些常用的函数式编程术语
2019/06/15 Javascript
vue实现百度语音合成的实例讲解
2019/10/14 Javascript
[01:35]2018完美盛典章节片——共竞
2018/12/17 DOTA
python登陆asp网站页面的实现代码
2015/01/14 Python
Python字典操作简明总结
2015/04/13 Python
python字符类型的一些方法小结
2016/05/16 Python
在python中使用正则表达式查找可嵌套字符串组
2017/10/24 Python
Python算法之求n个节点不同二叉树个数
2017/10/27 Python
使用Python抓取豆瓣影评数据的方法
2018/10/17 Python
使用Matplotlib 绘制精美的数学图形例子
2019/12/13 Python
使用tensorflow框架在Colab上跑通猫狗识别代码
2020/04/26 Python
Python实现aes加密解密多种方法解析
2020/05/15 Python
Pam & Gela官网:美国性感前卫女装品牌
2018/07/19 全球购物
《蒙娜丽莎之约》教学反思
2014/02/27 职场文书
担保贷款承诺书
2015/04/30 职场文书