最近一段时间一直在看AngularJS,趁着一点时间总结一下。

官网地址:http://angularjs.org/

先推荐几个教程

1. AngularJS入门教程 比较基础,是官方Tutorial的翻译。

2. 七步从AngularJS菜鸟到专家 也比较基础,制作了一个在线音乐播放网站。

3. AngularJS开发指南 这个教程比较全面,但我感觉翻译的有些晦涩难懂。

看过这些教程后,觉得AngularJS也懂一点了,就想用它干点事,就分析一下AngularJS写的todomvc吧。

Todomvc官网地址:http://todomvc.com/

项目的目录如下:

bower_components里放了两个文件夹,其中angular文件夹是用来一如angular.js文件的,todomvc-common文件夹里的放入了所有todo项目统一的css\js(只是用来生成左侧内容的,与项目无关)和图片。

js文件夹是大头,里面放了相应的controller(控制器)\directive(指令)\service(服务)和app.js。

test文件夹里放的是测试用的代码,不分析。

index.html是项目的view页面。

先来看一下app.js

  1. /*global angular */
  2. /*jshint unused:false */
  3. 'use strict';
  4.  
  5. /**
  6. * The main TodoMVC app module
  7. *
  8. * @type {angular.Module}
  9. */
  10. var todomvc = angular.module('todomvc', []);

就是定义了一个模块todomvc

再看一下services下的todoStorage.js

  1. /*global todomvc */
  2. 'use strict';
  3.  
  4. /**
  5. * Services that persists and retrieves TODOs from localStorage
  6. */
  7. todomvc.factory('todoStorage', function () {
  8. // todos JSON字符串存储的唯一标识
  9. var STORAGE_ID = 'todos-angularjs';
  10.  
  11. return {
  12. // 从localStorage中取出todos,并解析成JSON对象
  13. get: function () {
  14. return JSON.parse(localStorage.getItem(STORAGE_ID) || '[]');
  15. },
  16.  
  17. // 将todos对象转化成JSON字符串,并存入localStorage
  18. put: function (todos) {
  19. localStorage.setItem(STORAGE_ID, JSON.stringify(todos));
  20. }
  21. };
  22. });

使用factory方法创建了todoStorage的service方法,这个service方法的本质就是返回了两个方法get和put,两者都是用了JSON2和HTML5的特性。get将todos的内容从localStorage中取出,并解析成JSON,put将todos转化成JSON字符串,并存储到localStorage中。

再看一下directives下面的两个指令文件。

todoFocus.js

  1. /*global todomvc */
  2. 'use strict';
  3.  
  4. /**
  5. * Directive that places focus on the element it is applied to when the expression it binds to evaluates to true
  6. */
  7. todomvc.directive('todoFocus', function todoFocus($timeout) {
  8. return function (scope, elem, attrs) {
  9. // 为todoFocus属性的值添加监听
  10. scope.$watch(attrs.todoFocus, function (newVal) {
  11. if (newVal) {
  12. $timeout(function () {
  13. elem[0].focus();
  14. }, 0, false);
  15. }
  16. });
  17. };
  18. });

返回function的参数中,elem就是包含该指令的元素的数组,attrs是元素的所有属性、属性名等组成的对象。

其中用到了两个AngularJS的方法

$watch(watchExpression, listener, objectEquality) 注册一个侦听器回调,每当watchExpression变化时,监听回调将被执行。

$timeout(fn[, delay][, invokeApply]) 当timeout的值达到时,执行fn函数。

todoFocus.js创建了todoFocus指令。当一个元素拥有todoFocus属性时,该指令会为该元素的todoFocus属性的值添加监听,如果todoFocus属性的值改变成true,就会执行$timeout(function () {elem[0].focus();}, 0, false);其中的延迟时间为0秒,所以会立即执行elem[0].focus()。

todoEscape.js

  1. /*global todomvc */
  2. 'use strict';
  3.  
  4. /**
  5. * Directive that executes an expression when the element it is applied to gets
  6. * an `escape` keydown event.
  7. */
  8. todomvc.directive('todoEscape', function () {
  9. var ESCAPE_KEY = 27;
  10. return function (scope, elem, attrs) {
  11. elem.bind('keydown', function (event) {
  12. if (event.keyCode === ESCAPE_KEY) {
  13. scope.$apply(attrs.todoEscape);
  14. }
  15. });
  16. };
  17. });

todoEscape.js创建了todoEscape指令。当按下Escape键时,执行attrs.todoEscape的表达式。

看一下大头,controllers文件夹中的todoCtrl.js,这个文件略长,我就直接写注释了。

  1. /*global todomvc, angular */
  2. 'use strict';
  3.  
  4. /**
  5. * The main controller for the app. The controller:
  6. * - retrieves and persists the model via the todoStorage service
  7. * - exposes the model to the template and provides event handlers
  8. */
  9. todomvc.controller('TodoCtrl', function TodoCtrl($scope, $location, todoStorage, filterFilter) {
  10. // 从localStorage中获取todos
  11. var todos = $scope.todos = todoStorage.get();
  12.  
  13. // 记录新的todo
  14. $scope.newTodo = '';
  15. // 记录编辑过的todo
  16. $scope.editedTodo = null;
  17.  
  18. // 当todos的值改变时执行其中的方法
  19. $scope.$watch('todos', function (newValue, oldValue) {
  20. // 获取未完成的todos的数目
  21. $scope.remainingCount = filterFilter(todos, { completed: false }).length;
  22. // 获取已完成的todos的数目
  23. $scope.completedCount = todos.length - $scope.remainingCount;
  24. // 当且仅当$scope.remainingCount为0时,$scope.allChecked为true
  25. $scope.allChecked = !$scope.remainingCount;
  26. // 当todos的新值和旧值不相等时,向localStorage中存入todos
  27. if (newValue !== oldValue) { // This prevents unneeded calls to the local storage
  28. todoStorage.put(todos);
  29. }
  30. }, true);
  31.  
  32. if ($location.path() === '') {
  33. // 如果$location.path()为空,就设置为/
  34. $location.path('/');
  35. }
  36.  
  37. $scope.location = $location;
  38.  
  39. // 当location.path()的值改变时执行其中的方法
  40. $scope.$watch('location.path()', function (path) {
  41. // 获取状态的过滤器
  42. // 如果path为'/active',过滤器为{ completed: false }
  43. // 如果path为'/completed',过滤器为{ completed: true }
  44. // 否则,过滤器为null
  45. $scope.statusFilter = (path === '/active') ?
  46. { completed: false } : (path === '/completed') ?
  47. { completed: true } : null;
  48. });
  49.  
  50. // 添加一个新的todo
  51. $scope.addTodo = function () {
  52. var newTodo = $scope.newTodo.trim();
  53. if (!newTodo.length) {
  54. return;
  55. }
  56.  
  57. // 向todos里添加一个todo,completed属性默认为false
  58. todos.push({
  59. title: newTodo,
  60. completed: false
  61. });
  62.  
  63. // 置空
  64. $scope.newTodo = '';
  65. };
  66.  
  67. // 编辑一个todo
  68. $scope.editTodo = function (todo) {
  69. $scope.editedTodo = todo;
  70. // Clone the original todo to restore it on demand.
  71. // 保存编辑前的todo,为恢复编辑前做准备
  72. $scope.originalTodo = angular.extend({}, todo);
  73. };
  74.  
  75. // 编辑todo完成
  76. $scope.doneEditing = function (todo) {
  77. // 置空
  78. $scope.editedTodo = null;
  79. todo.title = todo.title.trim();
  80.  
  81. if (!todo.title) {
  82. // 如果todo的title为空,则移除该todo
  83. $scope.removeTodo(todo);
  84. }
  85. };
  86.  
  87. // 恢复编辑前的todo
  88. $scope.revertEditing = function (todo) {
  89. todos[todos.indexOf(todo)] = $scope.originalTodo;
  90. $scope.doneEditing($scope.originalTodo);
  91. };
  92.  
  93. // 移除todo
  94. $scope.removeTodo = function (todo) {
  95. todos.splice(todos.indexOf(todo), 1);
  96. };
  97.  
  98. // 清除已完成的todos
  99. $scope.clearCompletedTodos = function () {
  100. $scope.todos = todos = todos.filter(function (val) {
  101. return !val.completed;
  102. });
  103. };
  104.  
  105. // 标记所有的todo的状态(true或false)
  106. $scope.markAll = function (completed) {
  107. todos.forEach(function (todo) {
  108. todo.completed = completed;
  109. });
  110. };
  111. }); 

最后看一下index.html,这个文件我们一段一段的分析。

  1. <!doctype html>
  2. <html lang="en" ng-app="todomvc" data-framework="angularjs">
  3. <head>
  4. <meta charset="utf-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <title>AngularJS • TodoMVC</title>
  7. <link rel="stylesheet" href="bower_components/todomvc-common/base.css">
  8. <style>[ng-cloak] { display: none; }</style>
  9. </head>
  10. <body>
  11. <section id="todoapp" ng-controller="TodoCtrl">
  12. <header id="header">
  13. <h1>todos</h1>
  14. <form id="todo-form" ng-submit="addTodo()">
  15. <input id="new-todo" placeholder="What needs to be done?" ng-model="newTodo" autofocus>
  16. </form>
  17. </header>
  18. <section id="main" ng-show="todos.length" ng-cloak>
  19. <input id="toggle-all" type="checkbox" ng-model="allChecked" ng-click="markAll(allChecked)">
  20. <label for="toggle-all">Mark all as complete</label>
  21. <ul id="todo-list">
  22. <li ng-repeat="todo in todos | filter:statusFilter track by $index" ng-class="{completed: todo.completed, editing: todo == editedTodo}">
  23. <div class="view">
  24. <input class="toggle" type="checkbox" ng-model="todo.completed">
  25. <label ng-dblclick="editTodo(todo)">{{todo.title}}</label>
  26. <button class="destroy" ng-click="removeTodo(todo)"></button>
  27. </div>
  28. <form ng-submit="doneEditing(todo)">
  29. <input class="edit" ng-trim="false" ng-model="todo.title" todo-escape="revertEditing(todo)" ng-blur="doneEditing(todo)" todo-focus="todo == editedTodo">
  30. </form>
  31. </li>
  32. </ul>
  33. </section>
  34. <footer id="footer" ng-show="todos.length" ng-cloak>
  35. <span id="todo-count"><strong>{{remainingCount}}</strong>
  36. <ng-pluralize count="remainingCount" when="{ one: 'item left', other: 'items left' }"></ng-pluralize>
  37. </span>
  38. <ul id="filters">
  39. <li>
  40. <a ng-class="{selected: location.path() == '/'} " href="#/">All</a>
  41. </li>
  42. <li>
  43. <a ng-class="{selected: location.path() == '/active'}" href="#/active">Active</a>
  44. </li>
  45. <li>
  46. <a ng-class="{selected: location.path() == '/completed'}" href="#/completed">Completed</a>
  47. </li>
  48. </ul>
  49. <button id="clear-completed" ng-click="clearCompletedTodos()" ng-show="completedCount">Clear completed ({{completedCount}})</button>
  50. </footer>
  51. </section>
  52. <footer id="info">
  53. <p>Double-click to edit a todo</p>
  54. <p>Credits:
  55. <a href="http://twitter.com/cburgdorf">Christoph Burgdorf</a>,
  56. <a href="http://ericbidelman.com">Eric Bidelman</a>,
  57. <a href="http://jacobmumm.com">Jacob Mumm</a> and
  58. <a href="http://igorminar.com">Igor Minar</a>
  59. </p>
  60. <p>Part of <a href="http://todomvc.com">TodoMVC</a></p>
  61. </footer>
  62. <script src="bower_components/todomvc-common/base.js"></script>
  63. <script src="bower_components/angular/angular.js"></script>
  64. <script src="js/app.js"></script>
  65. <script src="js/controllers/todoCtrl.js"></script>
  66. <script src="js/services/todoStorage.js"></script>
  67. <script src="js/directives/todoFocus.js"></script>
  68. <script src="js/directives/todoEscape.js"></script>
  69. </body>
  70. </html>

首先是在最下面,引入相应的JS,这个就不多说了。

  1. <script src="bower_components/todomvc-common/base.js"></script>
  2. <script src="bower_components/angular/angular.js"></script>
  3. <script src="js/app.js"></script>
  4. <script src="js/controllers/todoCtrl.js"></script>
  5. <script src="js/services/todoStorage.js"></script>
  6. <script src="js/directives/todoFocus.js"></script>
  7. <script src="js/directives/todoEscape.js"></script>

定义style[ng-cloak],含有ng-cloak属性则不可见。

  1. <style>[ng-cloak] { display: none; }</style>

来看添加todo的html,绑定的model为newTodo,submit的方法是todoCtrl.js中的addTodo(),会添加一条todo,点击Enter,默认触发提交事件,就触发了addTodo()方法,添加了一条todo到todos中。

  1. <form id="todo-form" ng-submit="addTodo()">
  2. <input id="new-todo" placeholder="What needs to be done?" ng-model="newTodo" autofocus>
  3. </form>

再看展示todos的html

  1. <section id="main" ng-show="todos.length" ng-cloak>
  2. <input id="toggle-all" type="checkbox" ng-model="allChecked" ng-click="markAll(allChecked)">
  3. <label for="toggle-all">Mark all as complete</label>
  4. <ul id="todo-list">
  5. <li ng-repeat="todo in todos | filter:statusFilter track by $index" ng-class="{completed: todo.completed, editing: todo == editedTodo}">
  6. <div class="view">
  7. <input class="toggle" type="checkbox" ng-model="todo.completed">
  8. <label ng-dblclick="editTodo(todo)">{{todo.title}}</label>
  9. <button class="destroy" ng-click="removeTodo(todo)"></button>
  10. </div>
  11. <form ng-submit="doneEditing(todo)">
  12. <input class="edit" ng-trim="false" ng-model="todo.title" todo-escape="revertEditing(todo)" ng-blur="doneEditing(todo)" todo-focus="todo == editedTodo">
  13. </form>
  14. </li>
  15. </ul>
  16. </section>

section使用ngShow方法根据todos的长度判断是否显示,加上ng-cloak属性是为了在刚开始时不要显示出AngularJS未处理的页面。可以去掉刷新试一试。

其中id为toggle-all的checkbox绑定到allChecked model上,点击触发markAll(allChecked),将allChecked的值传入,标记所有的todos。

使用ngRepeat循环产生li标签,todo in todos | filter:statusFilter track by $index,循环todos,用statusFilter过滤,用$index追踪。ngClass绑定了两个class,{completed: todo.completed, editing: todo == editedTodo},如果todo.completed为true,添加completed class,如果todo==editedTodo,则添加editing class。class为toggle的checkbox绑定到todo.completed。todo标题展示的label绑定了双击事件,双击触发editTodo(todo),editTodo会将todo赋给editedTodo,然后会触发下面form中的todoFocus指令,这时候form中的input可见。按Esc就触发revertEditing(todo),恢复到编辑前,按Enter或者失去焦点就触发doneEditing(todo) ,保存编辑后的todo。class为destroy的button绑定了click事件,点击触发removeTodo(todo),删除掉该条todo。

最后看todos的统计信息展示的html

  1. <footer id="footer" ng-show="todos.length" ng-cloak>
  2. <span id="todo-count"><strong>{{remainingCount}}</strong>
  3. <ng-pluralize count="remainingCount" when="{ one: 'item left', other: 'items left' }"></ng-pluralize>
  4. </span>
  5. <ul id="filters">
  6. <li>
  7. <a ng-class="{selected: location.path() == '/'} " href="#/">All</a>
  8. </li>
  9. <li>
  10. <a ng-class="{selected: location.path() == '/active'}" href="#/active">Active</a>
  11. </li>
  12. <li>
  13. <a ng-class="{selected: location.path() == '/completed'}" href="#/completed">Completed</a>
  14. </li>
  15. </ul>
  16. <button id="clear-completed" ng-click="clearCompletedTodos()" ng-show="completedCount">Clear completed ({{completedCount}})</button>
  17. </footer>

ng-pluralize标签实现了当remainingCount个数为1时,显示 item left,否则显示 items left。

id为filters的ul标签中根据location.path()的内容不同,标记不同的a标签被选中。

id为clear-completed的button添加了点击事件,触发clearCompletedTodos(),清除掉所有已完成的todo。

分析到此结束,如有错误,或者有不明白的地方,请留言~~

 
 
分类: AngularJS

AngularJS

AngularJS的相关学习
摘要: AngularJS通过作用域中的事件处理通信。$on、$emit和$broadcast使得event、data在controller之间的传递变的简单。$emit只能向parent controller传递event与data,$broadcast只能向child controller传递event与data,$on用于接收event与data。阅读全文
posted @ 2014-04-22 00:08 疯狂的原始人 阅读(390) | 评论 (0) 编辑
摘要: 推荐几个AngularJS的教程,并分析了用AngularJS写的todomvc。阅读全文
posted @ 2013-12-31 12:34 疯狂的原始人 阅读(924) | 评论 (1) 编辑

看AngularJS的更多相关文章

  1. 摆脱DOM操作,从TodoMVC看angularJS

    取代jQuery? 我很久之前便听说了angularJS的大名,之前的leader也经常感叹angularJS的设计如何如何精妙,可叹一直没有机会深入了解,国庆长假因为没钱出游,倒是可以对他做一个了解 ...

  2. angularjs和ajax的结合使用 (一)

    好久没写文了.这是一篇关于easyui配合ajax使用 的文章, 顺带介绍angularjs的使用 以及让你感受到angularjs的威力.网上对于ajax 的文也是多如牛毛 .我就不直接 从那种原生 ...

  3. angularjs学习总结 详细教程(转载)

    1 前言 前端技术的发展是如此之快,各种优秀技术.优秀框架的出现简直让人目不暇接,紧跟时代潮流,学习掌握新知识自然是不敢怠慢. AngularJS是google在维护,其在国外已经十分火热,可是国内的 ...

  4. AngularJS学习笔记之依赖注入

    最近在看AngularJS权威指南,由于各种各样的原因(主要是因为我没有money,好讨厌的有木有......),于是我选择了网上下载电子版的(因为它不要钱,哈哈...),字体也蛮清晰的,总体效果还不 ...

  5. AngularJS的学习--TodoMVC的分析

    最近一段时间一直在看AngularJS,趁着一点时间总结一下. 官网地址:http://angularjs.org/ 先推荐几个教程 1. AngularJS入门教程 比较基础,是官方Tutorial ...

  6. [转载]angularjs学习总结 详细教程

    http://blog.csdn.net/yy374864125/article/details/41349417#t75 目录(?)[-] 前言 AngularJS概述 AngularJS是什么 A ...

  7. angularjs学习总结(~~很详细的教程)

    1 前言 前端技术的发展是如此之快,各种优秀技术.优秀框架的出现简直让人目不暇接,紧跟时代潮流,学习掌握新知识自然是不敢怠慢. AngularJS是google在维护,其在国外已经十分火热,可是国内的 ...

  8. 转: angularjs学习总结(~~很详细的教程)

    1 前言 前端技术的发展是如此之快,各种优秀技术.优秀框架的出现简直让人目不暇接,紧跟时代潮流,学习掌握新知识自然是不敢怠慢. AngularJS是google在维护,其在国外已经十分火热,可是国内的 ...

  9. 媲美jQuery的JS框架----AngularJS(二)

    前言 对于AngularJS什么,小编在这就不多做介绍了.大家可以看小编的上一篇博客. 言归正传,小编在上一篇博客中介绍了AngularJS中的指令.表达式还有非常实用的三种服务.接下来,带大家看一看 ...

随机推荐

  1. Javascript中的深拷贝和浅拷贝

    var obj = { a:1, arr: [1,2] }; var obj1 = obj; //浅复制 var obj2 = deepCopy(obj); //深复制 javascript中创建对象 ...

  2. 由于抽签HT For Web ComboBox下拉框组件

    传统HTML5的下拉框select仅仅能实现简单的文字下拉列表,而HT for Web通用组件中ComboBox不仅可以实现传统HTML5下拉框效果,并且可以在文本框和下拉列表中加入自己定义的小图标, ...

  3. a^b%c 的三种形式

    求a^b%c,(1  <= a,b <= 2^62, 1 <= c <= 10^9) 最主要的高速幂 _LL mod_exp(_LL a, _LL b, int c) { _L ...

  4. 《Javascript权威指南》十六学习笔记:BOM资源---BOM基本应用

    BOM基本应用包括:管理浏览器历史记录.得到处理和解决浏览器的信息.本文介绍了这些应用程序. 一.浏览历史管理 1.history对象的方法和属性 History 对象包括用户(在浏览器窗体中)訪问过 ...

  5. Git 命令速查表

    Git 命令速查表 1.常用的Git命令 命令 简要说明 git add 添加至暂存区 git add-interactive 交互式添加 git apply 应用补丁 git am 应用邮件格式补丁 ...

  6. 大数据系列修炼-Scala课程08

    接下来会讲解关于各种模式匹配,从中就会知道模式匹配的重要性 关于Type.Array.List.Tuple模式解析 1.Type模式匹配代码解析 //关于Type类型的模式匹配 //匹配 Int类型. ...

  7. 使用SAX解析XML文件

    SAX这是Simple API for XML缩写,它不是由引起W3C拟议标准正式.尽管如此,使用SAX很少几个,点儿全部的XML解析器都会支持它. 与DOM比較而言,SAX是一种轻量型的方法. 我们 ...

  8. 【Head First Javascript】学习笔记0——自己制作chm参考手册素材

    变量声明:var 常量声明:const 数据格式转换: 1.转换函数 parseInt(A):把字符串A转换成整数:其中A为只包含数字的字符串 parseFloat(A):把字符串A转换成浮点数:其中 ...

  9. Cgroup maintainer丽泽范:解剖Linux核心容器技术

    摘要:Cgroup和namespace等内核特性如何出现,在社区处于如何的开发状况?Docker如火如荼.内核社区是否会因此加紧完好容器技术的隔离性安全性?华为Linux内核高级project师李泽帆 ...

  10. java web.xml listener servlet 和filter加载顺序

    在该项目中总会遇到一些关于加载的优先问题.最近遇到了同样的类别似的,所以,如果你发现信息汇总下,以下是转载其他一些人,毕竟,人们写的不错.它不重复创建的轮.只是略作修改自己的观点. 首先能够肯定的是, ...