今天我们来818《angularjs in action》的第三章controller和view。
1.Big Picture概览图
- View是angularjs编译html后呈现出来的,需要编译的是controller中的定义的属性和方法以及directive中定义的指令。
- View和controller是独立开来的,他们之间的纽带就是图中间的胶水——scope。Controller负责向scope中提供属性和方法,便于和view层面的html进行交互。
- 方便起见,我们通常将controller和scope统一视为ViewModel。这样就引出了我们见到的一个概念MVVM框架(Model-View-ViewModel),这也是angularjs遵循的框架理念。具体见下图
仔细看看图,再想想还有一个众所周知的概念——MVC,对比下来,你是否体会到了什么?
2.What Is An Angularjs View
- 如果你打开angularjs的官网,你将会看到这样一句话“HTML enchanced for web apps”。这在一定程度上肯定了angularjs也揭露了angularjs一个重要的特性,传统html标签以外的指令。
- 在scope中存入一个变量值$scope.name,便可以在html中通过<p>{{name}}</p>的方式展示出来。如果你想将一个数组放入scope中$scope.values=[1,2,3,4],那也没问题,只需要在html中写上<p ng-repeat=”value in values”>{{value}}</p>,就可以遍历并展示整个数组。
- Angularjs提供了很多内置的指令,但是面对错综复杂的真实世界,angularjs显得有些力不从心。所以angularjs团队提供用户可以编写自定义的指令。(这是个long story,这里先不说,让我们继续controller和view之间的那些事儿~~~)
- 言归正传,View到底是什么?简而言之,就是经过angularjs编译DOM得到的页面呈现。那我们就好好理解下“编译”二字的具体含义。
- 编译分为两部分:compilation阶段和linking阶段。
- 当html加载完成后,angularjs就开始解析DOM节后并编译其中包含的directives,这就是compilation阶段的工作;
- 一旦html中的所有元素都编译完了,angularjs就开始进入linking阶段,负责链接到每个angularjs编译条目对应的scope实例。
- 当angularjs的template被链接到相应的controller之后,就通过scope完成了view和controller之间的联系,就犹如上图中的胶水一般。具体可以参见图
3.What Is An Angularjs Controller
我们说通过胶水scope建立起view和controller之间的联系和交互。那么scope到底是什么,它又是如何实现view和controller之间相互通信的?深究后发现,scope就是一个带有事件机制的POJO(Plain Old Javascript Object)。这些事件促成了angularjs中的digest cycle,从而同步view端和controller端,具体如下图:
Angularjs有着一套自己的事件机制,添加事件,然后在应用的任何地方响应。发射事件的方式有两种:$broadcast和$emit,他们除了发射事件的方向不一样意外,别无二致。负责监听和响应使用的是$on。
要使用事件机制就要有scope对象,比如你要在一个service中broadcast一个事件,就需要注入$rootScope。当然了,一般来说我们不直接注入$rootScope,而是将$rootScope注入放在一个高level的地方。$broadcast是向下发送事件,所以需要确保所有的scope对象都能够响应事件,因为所有的scope对象都在$rootScope对象下面。一般来说,开发者都使用promises来处理services中的异步事件。
4.Properites and Expressions
接下来我们要搞懂两个问题:绑定属性和执行表达式。
4.1 ngRepeat
你如何展示一个对象数组,而且实现并没有定义他们的布局等等,如果有个东西能够定义一个template然后只要repeat每个对象就可以展示是不是炫爆了,没错,angularjs中的ngRepeat为您带来了福音。
我们定义一个对象数组,其中有各个不同的status,通过ngRepeat来遍历每个status然后显示到页面上。
这里的status in storyboard.statuses就是遍历出controller中的statues数组,然后通过{{status.name}}实现双向绑定,取到controller中各个status对应的name(To Do, In Progress, Code Review, QA Review, Verified)
4.2 Filters
过滤器可以过滤出你想要的数据格式和内容。比如在上例中可以使用|filter:{status:status.name},,这个表达式意思是说只返回那些匹配status.name的stories。
最终得到如下结果:
4.3 Expression
到目前为止,已经知道如何通过template和ngRepeat来展示stories集合了,那么如何展示、更新和删除单个story detail页面呢?
- display a story
这里做了一些准备工作,一个currentStory和editStory。(这里可以通过http://www.tuicool.com/articles/En6Jve了解下copy和extend的区别,深拷贝和浅拷贝)
页面中定义如下:
注意:通过这个例子,可以看出angularjs是如何传值,明白了angularjs这种里面的函数的参数的值从何而来。从本例来看,在页面中通过ng-repeat得到当前current的这个story,并在ng-click事件中添加storyboard.setCurrentStory(story)函数,而且将story作为参数传入,并在StoryboardController.js的setCurrentStory有其具体实现
- Update a story
更新story就是更新storyboard.detailForm中的元素,并将更新的只直接reflected到storyboard.editedStory中去(如果觉得有点迷糊,记得结合项目源码看)。这里主要有storyboard.updateCancel(取消更新)和storyboard.updateSotry(确认更新)。 其中storyboard.updateCancel通过调用resetForm是的form恢复初始状态,updateStory通过遍历每个属性并写入到storyboard.currentStory对象中,一旦这个操作完成,还需要执行resetForm使得表格恢复初始状态。
- Create a story
创建一个story和update的过程很像,只是我们不需要再选择current story这个步骤了,直接创建后push保存就ok了。当storyboard.currentStory为null时,我们就隐藏update按钮同时显示create的按钮。
- Delete a story
删除一个story只需要得到从前台页面通过ng-click传过来的id就可以实现删除了
至此,我们啃完了第三章,大概内容有:
- 了解angularjs中的view层;
- 了解angularjs中的controller用于定义属性和方法存放在scope上,并且可以和view交互;
- 了解scope是一个POJO,是view和controller之间的胶水;
- 当属性在scope中声明,意味着可以直接绑定到view上;
- ngRepeat的介绍和使用;
- filter的介绍和使用;
- display、update、create、delete a story.
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!如果您想持续关注我的文章,请扫描二维码,关注JackieZheng的微信公众号,我会将我的文章推送给您,并和您一起分享我日常阅读过的优质文章。