看AngularJS
最近一段时间一直在看AngularJS,趁着一点时间总结一下。
先推荐几个教程
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

- /*global angular */
- /*jshint unused:false */
- 'use strict';
- /**
- * The main TodoMVC app module
- *
- * @type {angular.Module}
- */
- var todomvc = angular.module('todomvc', []);

就是定义了一个模块todomvc
再看一下services下的todoStorage.js

- /*global todomvc */
- 'use strict';
- /**
- * Services that persists and retrieves TODOs from localStorage
- */
- todomvc.factory('todoStorage', function () {
- // todos JSON字符串存储的唯一标识
- var STORAGE_ID = 'todos-angularjs';
- return {
- // 从localStorage中取出todos,并解析成JSON对象
- get: function () {
- return JSON.parse(localStorage.getItem(STORAGE_ID) || '[]');
- },
- // 将todos对象转化成JSON字符串,并存入localStorage
- put: function (todos) {
- localStorage.setItem(STORAGE_ID, JSON.stringify(todos));
- }
- };
- });

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

- /*global todomvc */
- 'use strict';
- /**
- * Directive that places focus on the element it is applied to when the expression it binds to evaluates to true
- */
- todomvc.directive('todoFocus', function todoFocus($timeout) {
- return function (scope, elem, attrs) {
- // 为todoFocus属性的值添加监听
- scope.$watch(attrs.todoFocus, function (newVal) {
- if (newVal) {
- $timeout(function () {
- elem[0].focus();
- }, 0, false);
- }
- });
- };
- });

返回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

- /*global todomvc */
- 'use strict';
- /**
- * Directive that executes an expression when the element it is applied to gets
- * an `escape` keydown event.
- */
- todomvc.directive('todoEscape', function () {
- var ESCAPE_KEY = 27;
- return function (scope, elem, attrs) {
- elem.bind('keydown', function (event) {
- if (event.keyCode === ESCAPE_KEY) {
- scope.$apply(attrs.todoEscape);
- }
- });
- };
- });

todoEscape.js创建了todoEscape指令。当按下Escape键时,执行attrs.todoEscape的表达式。
看一下大头,controllers文件夹中的todoCtrl.js,这个文件略长,我就直接写注释了。

- /*global todomvc, angular */
- 'use strict';
- /**
- * The main controller for the app. The controller:
- * - retrieves and persists the model via the todoStorage service
- * - exposes the model to the template and provides event handlers
- */
- todomvc.controller('TodoCtrl', function TodoCtrl($scope, $location, todoStorage, filterFilter) {
- // 从localStorage中获取todos
- var todos = $scope.todos = todoStorage.get();
- // 记录新的todo
- $scope.newTodo = '';
- // 记录编辑过的todo
- $scope.editedTodo = null;
- // 当todos的值改变时执行其中的方法
- $scope.$watch('todos', function (newValue, oldValue) {
- // 获取未完成的todos的数目
- $scope.remainingCount = filterFilter(todos, { completed: false }).length;
- // 获取已完成的todos的数目
- $scope.completedCount = todos.length - $scope.remainingCount;
- // 当且仅当$scope.remainingCount为0时,$scope.allChecked为true
- $scope.allChecked = !$scope.remainingCount;
- // 当todos的新值和旧值不相等时,向localStorage中存入todos
- if (newValue !== oldValue) { // This prevents unneeded calls to the local storage
- todoStorage.put(todos);
- }
- }, true);
- if ($location.path() === '') {
- // 如果$location.path()为空,就设置为/
- $location.path('/');
- }
- $scope.location = $location;
- // 当location.path()的值改变时执行其中的方法
- $scope.$watch('location.path()', function (path) {
- // 获取状态的过滤器
- // 如果path为'/active',过滤器为{ completed: false }
- // 如果path为'/completed',过滤器为{ completed: true }
- // 否则,过滤器为null
- $scope.statusFilter = (path === '/active') ?
- { completed: false } : (path === '/completed') ?
- { completed: true } : null;
- });
- // 添加一个新的todo
- $scope.addTodo = function () {
- var newTodo = $scope.newTodo.trim();
- if (!newTodo.length) {
- return;
- }
- // 向todos里添加一个todo,completed属性默认为false
- todos.push({
- title: newTodo,
- completed: false
- });
- // 置空
- $scope.newTodo = '';
- };
- // 编辑一个todo
- $scope.editTodo = function (todo) {
- $scope.editedTodo = todo;
- // Clone the original todo to restore it on demand.
- // 保存编辑前的todo,为恢复编辑前做准备
- $scope.originalTodo = angular.extend({}, todo);
- };
- // 编辑todo完成
- $scope.doneEditing = function (todo) {
- // 置空
- $scope.editedTodo = null;
- todo.title = todo.title.trim();
- if (!todo.title) {
- // 如果todo的title为空,则移除该todo
- $scope.removeTodo(todo);
- }
- };
- // 恢复编辑前的todo
- $scope.revertEditing = function (todo) {
- todos[todos.indexOf(todo)] = $scope.originalTodo;
- $scope.doneEditing($scope.originalTodo);
- };
- // 移除todo
- $scope.removeTodo = function (todo) {
- todos.splice(todos.indexOf(todo), 1);
- };
- // 清除已完成的todos
- $scope.clearCompletedTodos = function () {
- $scope.todos = todos = todos.filter(function (val) {
- return !val.completed;
- });
- };
- // 标记所有的todo的状态(true或false)
- $scope.markAll = function (completed) {
- todos.forEach(function (todo) {
- todo.completed = completed;
- });
- };
- });

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

- <!doctype html>
- <html lang="en" ng-app="todomvc" data-framework="angularjs">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <title>AngularJS • TodoMVC</title>
- <link rel="stylesheet" href="bower_components/todomvc-common/base.css">
- <style>[ng-cloak] { display: none; }</style>
- </head>
- <body>
- <section id="todoapp" ng-controller="TodoCtrl">
- <header id="header">
- <h1>todos</h1>
- <form id="todo-form" ng-submit="addTodo()">
- <input id="new-todo" placeholder="What needs to be done?" ng-model="newTodo" autofocus>
- </form>
- </header>
- <section id="main" ng-show="todos.length" ng-cloak>
- <input id="toggle-all" type="checkbox" ng-model="allChecked" ng-click="markAll(allChecked)">
- <label for="toggle-all">Mark all as complete</label>
- <ul id="todo-list">
- <li ng-repeat="todo in todos | filter:statusFilter track by $index" ng-class="{completed: todo.completed, editing: todo == editedTodo}">
- <div class="view">
- <input class="toggle" type="checkbox" ng-model="todo.completed">
- <label ng-dblclick="editTodo(todo)">{{todo.title}}</label>
- <button class="destroy" ng-click="removeTodo(todo)"></button>
- </div>
- <form ng-submit="doneEditing(todo)">
- <input class="edit" ng-trim="false" ng-model="todo.title" todo-escape="revertEditing(todo)" ng-blur="doneEditing(todo)" todo-focus="todo == editedTodo">
- </form>
- </li>
- </ul>
- </section>
- <footer id="footer" ng-show="todos.length" ng-cloak>
- <span id="todo-count"><strong>{{remainingCount}}</strong>
- <ng-pluralize count="remainingCount" when="{ one: 'item left', other: 'items left' }"></ng-pluralize>
- </span>
- <ul id="filters">
- <li>
- <a ng-class="{selected: location.path() == '/'} " href="#/">All</a>
- </li>
- <li>
- <a ng-class="{selected: location.path() == '/active'}" href="#/active">Active</a>
- </li>
- <li>
- <a ng-class="{selected: location.path() == '/completed'}" href="#/completed">Completed</a>
- </li>
- </ul>
- <button id="clear-completed" ng-click="clearCompletedTodos()" ng-show="completedCount">Clear completed ({{completedCount}})</button>
- </footer>
- </section>
- <footer id="info">
- <p>Double-click to edit a todo</p>
- <p>Credits:
- <a href="http://twitter.com/cburgdorf">Christoph Burgdorf</a>,
- <a href="http://ericbidelman.com">Eric Bidelman</a>,
- <a href="http://jacobmumm.com">Jacob Mumm</a> and
- <a href="http://igorminar.com">Igor Minar</a>
- </p>
- <p>Part of <a href="http://todomvc.com">TodoMVC</a></p>
- </footer>
- <script src="bower_components/todomvc-common/base.js"></script>
- <script src="bower_components/angular/angular.js"></script>
- <script src="js/app.js"></script>
- <script src="js/controllers/todoCtrl.js"></script>
- <script src="js/services/todoStorage.js"></script>
- <script src="js/directives/todoFocus.js"></script>
- <script src="js/directives/todoEscape.js"></script>
- </body>
- </html>

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

- <script src="bower_components/todomvc-common/base.js"></script>
- <script src="bower_components/angular/angular.js"></script>
- <script src="js/app.js"></script>
- <script src="js/controllers/todoCtrl.js"></script>
- <script src="js/services/todoStorage.js"></script>
- <script src="js/directives/todoFocus.js"></script>
- <script src="js/directives/todoEscape.js"></script>

定义style[ng-cloak],含有ng-cloak属性则不可见。
- <style>[ng-cloak] { display: none; }</style>
来看添加todo的html,绑定的model为newTodo,submit的方法是todoCtrl.js中的addTodo(),会添加一条todo,点击Enter,默认触发提交事件,就触发了addTodo()方法,添加了一条todo到todos中。
- <form id="todo-form" ng-submit="addTodo()">
- <input id="new-todo" placeholder="What needs to be done?" ng-model="newTodo" autofocus>
- </form>
再看展示todos的html

- <section id="main" ng-show="todos.length" ng-cloak>
- <input id="toggle-all" type="checkbox" ng-model="allChecked" ng-click="markAll(allChecked)">
- <label for="toggle-all">Mark all as complete</label>
- <ul id="todo-list">
- <li ng-repeat="todo in todos | filter:statusFilter track by $index" ng-class="{completed: todo.completed, editing: todo == editedTodo}">
- <div class="view">
- <input class="toggle" type="checkbox" ng-model="todo.completed">
- <label ng-dblclick="editTodo(todo)">{{todo.title}}</label>
- <button class="destroy" ng-click="removeTodo(todo)"></button>
- </div>
- <form ng-submit="doneEditing(todo)">
- <input class="edit" ng-trim="false" ng-model="todo.title" todo-escape="revertEditing(todo)" ng-blur="doneEditing(todo)" todo-focus="todo == editedTodo">
- </form>
- </li>
- </ul>
- </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

- <footer id="footer" ng-show="todos.length" ng-cloak>
- <span id="todo-count"><strong>{{remainingCount}}</strong>
- <ng-pluralize count="remainingCount" when="{ one: 'item left', other: 'items left' }"></ng-pluralize>
- </span>
- <ul id="filters">
- <li>
- <a ng-class="{selected: location.path() == '/'} " href="#/">All</a>
- </li>
- <li>
- <a ng-class="{selected: location.path() == '/active'}" href="#/active">Active</a>
- </li>
- <li>
- <a ng-class="{selected: location.path() == '/completed'}" href="#/completed">Completed</a>
- </li>
- </ul>
- <button id="clear-completed" ng-click="clearCompletedTodos()" ng-show="completedCount">Clear completed ({{completedCount}})</button>
- </footer>

ng-pluralize标签实现了当remainingCount个数为1时,显示 item left,否则显示 items left。
id为filters的ul标签中根据location.path()的内容不同,标记不同的a标签被选中。
id为clear-completed的button添加了点击事件,触发clearCompletedTodos(),清除掉所有已完成的todo。
分析到此结束,如有错误,或者有不明白的地方,请留言~~
AngularJS
看AngularJS的更多相关文章
- 摆脱DOM操作,从TodoMVC看angularJS
取代jQuery? 我很久之前便听说了angularJS的大名,之前的leader也经常感叹angularJS的设计如何如何精妙,可叹一直没有机会深入了解,国庆长假因为没钱出游,倒是可以对他做一个了解 ...
- angularjs和ajax的结合使用 (一)
好久没写文了.这是一篇关于easyui配合ajax使用 的文章, 顺带介绍angularjs的使用 以及让你感受到angularjs的威力.网上对于ajax 的文也是多如牛毛 .我就不直接 从那种原生 ...
- angularjs学习总结 详细教程(转载)
1 前言 前端技术的发展是如此之快,各种优秀技术.优秀框架的出现简直让人目不暇接,紧跟时代潮流,学习掌握新知识自然是不敢怠慢. AngularJS是google在维护,其在国外已经十分火热,可是国内的 ...
- AngularJS学习笔记之依赖注入
最近在看AngularJS权威指南,由于各种各样的原因(主要是因为我没有money,好讨厌的有木有......),于是我选择了网上下载电子版的(因为它不要钱,哈哈...),字体也蛮清晰的,总体效果还不 ...
- AngularJS的学习--TodoMVC的分析
最近一段时间一直在看AngularJS,趁着一点时间总结一下. 官网地址:http://angularjs.org/ 先推荐几个教程 1. AngularJS入门教程 比较基础,是官方Tutorial ...
- [转载]angularjs学习总结 详细教程
http://blog.csdn.net/yy374864125/article/details/41349417#t75 目录(?)[-] 前言 AngularJS概述 AngularJS是什么 A ...
- angularjs学习总结(~~很详细的教程)
1 前言 前端技术的发展是如此之快,各种优秀技术.优秀框架的出现简直让人目不暇接,紧跟时代潮流,学习掌握新知识自然是不敢怠慢. AngularJS是google在维护,其在国外已经十分火热,可是国内的 ...
- 转: angularjs学习总结(~~很详细的教程)
1 前言 前端技术的发展是如此之快,各种优秀技术.优秀框架的出现简直让人目不暇接,紧跟时代潮流,学习掌握新知识自然是不敢怠慢. AngularJS是google在维护,其在国外已经十分火热,可是国内的 ...
- 媲美jQuery的JS框架----AngularJS(二)
前言 对于AngularJS什么,小编在这就不多做介绍了.大家可以看小编的上一篇博客. 言归正传,小编在上一篇博客中介绍了AngularJS中的指令.表达式还有非常实用的三种服务.接下来,带大家看一看 ...
随机推荐
- Javascript中的深拷贝和浅拷贝
var obj = { a:1, arr: [1,2] }; var obj1 = obj; //浅复制 var obj2 = deepCopy(obj); //深复制 javascript中创建对象 ...
- 由于抽签HT For Web ComboBox下拉框组件
传统HTML5的下拉框select仅仅能实现简单的文字下拉列表,而HT for Web通用组件中ComboBox不仅可以实现传统HTML5下拉框效果,并且可以在文本框和下拉列表中加入自己定义的小图标, ...
- 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 ...
- 《Javascript权威指南》十六学习笔记:BOM资源---BOM基本应用
BOM基本应用包括:管理浏览器历史记录.得到处理和解决浏览器的信息.本文介绍了这些应用程序. 一.浏览历史管理 1.history对象的方法和属性 History 对象包括用户(在浏览器窗体中)訪问过 ...
- Git 命令速查表
Git 命令速查表 1.常用的Git命令 命令 简要说明 git add 添加至暂存区 git add-interactive 交互式添加 git apply 应用补丁 git am 应用邮件格式补丁 ...
- 大数据系列修炼-Scala课程08
接下来会讲解关于各种模式匹配,从中就会知道模式匹配的重要性 关于Type.Array.List.Tuple模式解析 1.Type模式匹配代码解析 //关于Type类型的模式匹配 //匹配 Int类型. ...
- 使用SAX解析XML文件
SAX这是Simple API for XML缩写,它不是由引起W3C拟议标准正式.尽管如此,使用SAX很少几个,点儿全部的XML解析器都会支持它. 与DOM比較而言,SAX是一种轻量型的方法. 我们 ...
- 【Head First Javascript】学习笔记0——自己制作chm参考手册素材
变量声明:var 常量声明:const 数据格式转换: 1.转换函数 parseInt(A):把字符串A转换成整数:其中A为只包含数字的字符串 parseFloat(A):把字符串A转换成浮点数:其中 ...
- Cgroup maintainer丽泽范:解剖Linux核心容器技术
摘要:Cgroup和namespace等内核特性如何出现,在社区处于如何的开发状况?Docker如火如荼.内核社区是否会因此加紧完好容器技术的隔离性安全性?华为Linux内核高级project师李泽帆 ...
- java web.xml listener servlet 和filter加载顺序
在该项目中总会遇到一些关于加载的优先问题.最近遇到了同样的类别似的,所以,如果你发现信息汇总下,以下是转载其他一些人,毕竟,人们写的不错.它不重复创建的轮.只是略作修改自己的观点. 首先能够肯定的是, ...