就是定义了一个模块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; }); }; });