AngularJS应用程序:待办事项列表
时间:2021-11-29 作者:匿名
待办事项的插件初始界面如上图红框内容,没有任何选项,当你在输入框中输入并按下回车后,你输入的内容将会显示在下面,并且能够被保存下来,下次打开浏览器时还会存在。
上面有3个按钮“全部”“需要做”“已完成”,选择后只显示相对应的条目。
待办事项完成后可以勾选起来,右侧的红叉可以删除条目,有勾选项目后,右下角将出现“清除已完成”的按钮,可以清理掉已经勾选的项目。
开发这个应用程序,我们使用HTML、CSS和AngularJS。 引用了AngularJS的angular-route.js和base.js等文件,并且编写了其他几个js,下面列出所有代码:
index.html
<!doctype html> <html data-framework="angularjs"> <head> <meta charset="utf-8"> <link rel="stylesheet" href="node_modules/todomvc-common/base.css"> <link rel="stylesheet" href="node_modules/todomvc-app-css/index.css"> <style> [ng-cloak] { display: none; } body{background:#EEE;} </style> </head> <body ng-app="todomvc"> <ng-view /> <script type="text/ng-template" id="todomvc-index.html"> <section id="todoapp"> <header id="header"> <form id="todo-form" ng-submit="addTodo()"> <input id="new-todo" placeholder="输入待办事项列表" ng-model="newTodo" ng-disabled="saving" 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> <input type="checkbox" ng-model="todo.completed" ng-change="toggleCompleted(todo)"> <label ng-dblclick="editTodo(todo)">{{todo.title}}</label> <button ng-click="removeTodo(todo)"></button> </div> <form ng-submit="saveEdits(todo, 'submit')"> <input ng-trim="false" ng-model="todo.title" todo-escape="revertEdits(todo)" ng-blur="saveEdits(todo, 'blur')" 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: status == ''} " href="#/">全部</a> </li> <li> <a ng-class="{selected: status == 'active'}" href="#/active">需要做</a> </li> <li> <a ng-class="{selected: status == 'completed'}" href="#/completed">已完成</a> </li> </ul> <button id="clear-completed" ng-click="clearCompletedTodos()" ng-show="completedCount">清除已完成</button> </footer> </section> </script> <script src="node_modules/todomvc-common/base.js"></script> <script src="node_modules/angular/angular.js"></script> <script src="node_modules/angular-route/angular-route.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>
todoCtrl.js
angular.module('todomvc') .controller('TodoCtrl', function TodoCtrl($scope, $routeParams, $filter, store) { 'use strict'; var todos = $scope.todos = store.todos; $scope.newTodo = ''; $scope.editedTodo = null; $scope.$watch('todos', function () { $scope.remainingCount = $filter('filter')(todos, { completed: false }).length; $scope.completedCount = todos.length - $scope.remainingCount; $scope.allChecked = !$scope.remainingCount; }, true); // Monitor the current route for changes and adjust the filter accordingly. $scope.$on('$routeChangeSuccess', function () { var status = $scope.status = $routeParams.status || ''; $scope.statusFilter = (status === 'active') ? { completed: false } : (status === 'completed') ? { completed: true } : {}; }); $scope.addTodo = function () { var newTodo = { title: $scope.newTodo.trim(), completed: false }; if (!newTodo.title) { return; } $scope.saving = true; store.insert(newTodo) .then(function success() { $scope.newTodo = ''; }) .finally(function () { $scope.saving = false; }); }; $scope.editTodo = function (todo) { $scope.editedTodo = todo; // Clone the original todo to restore it on demand. $scope.originalTodo = angular.extend({}, todo); }; $scope.saveEdits = function (todo, event) { // Blur events are automatically triggered after the form submit event. // This does some unfortunate logic handling to prevent saving twice. if (event === 'blur' && $scope.saveEvent === 'submit') { $scope.saveEvent = null; return; } $scope.saveEvent = event; if ($scope.reverted) { // Todo edits were reverted-- don't save. $scope.reverted = null; return; } todo.title = todo.title.trim(); if (todo.title === $scope.originalTodo.title) { $scope.editedTodo = null; return; } store[todo.title ? 'put' : 'delete'](todo) .then(function success() {}, function error() { todo.title = $scope.originalTodo.title; }) .finally(function () { $scope.editedTodo = null; }); }; $scope.revertEdits = function (todo) { todos[todos.indexOf(todo)] = $scope.originalTodo; $scope.editedTodo = null; $scope.originalTodo = null; $scope.reverted = true; }; $scope.removeTodo = function (todo) { store.delete(todo); }; $scope.saveTodo = function (todo) { store.put(todo); }; $scope.toggleCompleted = function (todo, completed) { if (angular.isDefined(completed)) { todo.completed = completed; } store.put(todo, todos.indexOf(todo)) .then(function success() {}, function error() { todo.completed = !todo.completed; }); }; $scope.clearCompletedTodos = function () { store.clearCompleted(); }; $scope.markAll = function (completed) { todos.forEach(function (todo) { if (todo.completed !== completed) { $scope.toggleCompleted(todo, completed); } }); }; });
todoEscape.js
angular.module('todomvc') .directive('todoEscape', function () { 'use strict'; var ESCAPE_KEY = 27; return function (scope, elem, attrs) { elem.bind('keydown', function (event) { if (event.keyCode === ESCAPE_KEY) { scope.$apply(attrs.todoEscape); } }); scope.$on('$destroy', function () { elem.unbind('keydown'); }); }; });
todoFocus.js
angular.module('todomvc') .directive('todoFocus', function todoFocus($timeout) { 'use strict'; return function (scope, elem, attrs) { scope.$watch(attrs.todoFocus, function (newVal) { if (newVal) { $timeout(function () { elem[0].focus(); }, 0, false); } }); }; });
todoStorage.js
angular.module('todomvc') .factory('todoStorage', function ($http, $injector) { 'use strict'; // Detect if an API backend is present. If so, return the API module, else // hand off the localStorage adapter return $http.get('/api') .then(function () { return $injector.get('api'); }, function () { return $injector.get('localStorage'); }); }) .factory('api', function ($http) { 'use strict'; var store = { todos: [], clearCompleted: function () { var originalTodos = store.todos.slice(0); var completeTodos = []; var incompleteTodos = []; store.todos.forEach(function (todo) { if (todo.completed) { completeTodos.push(todo); } else { incompleteTodos.push(todo); } }); angular.copy(incompleteTodos, store.todos); return $http.delete('/api/todos') .then(function success() { return store.todos; }, function error() { angular.copy(originalTodos, store.todos); return originalTodos; }); }, delete: function (todo) { var originalTodos = store.todos.slice(0); store.todos.splice(store.todos.indexOf(todo), 1); return $http.delete('/api/todos/' + todo.id) .then(function success() { return store.todos; }, function error() { angular.copy(originalTodos, store.todos); return originalTodos; }); }, get: function () { return $http.get('/api/todos') .then(function (resp) { angular.copy(resp.data, store.todos); return store.todos; }); }, insert: function (todo) { var originalTodos = store.todos.slice(0); return $http.post('/api/todos', todo) .then(function success(resp) { todo.id = resp.data.id; store.todos.push(todo); return store.todos; }, function error() { angular.copy(originalTodos, store.todos); return store.todos; }); }, put: function (todo) { var originalTodos = store.todos.slice(0); return $http.put('/api/todos/' + todo.id, todo) .then(function success() { return store.todos; }, function error() { angular.copy(originalTodos, store.todos); return originalTodos; }); } }; return store; }) .factory('localStorage', function ($q) { 'use strict'; var STORAGE_ID = 'todos-angularjs'; var store = { todos: [], _getFromLocalStorage: function () { return JSON.parse(localStorage.getItem(STORAGE_ID) || '[]'); }, _saveToLocalStorage: function (todos) { localStorage.setItem(STORAGE_ID, JSON.stringify(todos)); }, clearCompleted: function () { var deferred = $q.defer(); var completeTodos = []; var incompleteTodos = []; store.todos.forEach(function (todo) { if (todo.completed) { completeTodos.push(todo); } else { incompleteTodos.push(todo); } }); angular.copy(incompleteTodos, store.todos); store._saveToLocalStorage(store.todos); deferred.resolve(store.todos); return deferred.promise; }, delete: function (todo) { var deferred = $q.defer(); store.todos.splice(store.todos.indexOf(todo), 1); store._saveToLocalStorage(store.todos); deferred.resolve(store.todos); return deferred.promise; }, get: function () { var deferred = $q.defer(); angular.copy(store._getFromLocalStorage(), store.todos); deferred.resolve(store.todos); return deferred.promise; }, insert: function (todo) { var deferred = $q.defer(); store.todos.push(todo); store._saveToLocalStorage(store.todos); deferred.resolve(store.todos); return deferred.promise; }, put: function (todo, index) { var deferred = $q.defer(); store.todos[index] = todo; store._saveToLocalStorage(store.todos); deferred.resolve(store.todos); return deferred.promise; } }; return store; });
app.js
angular.module('todomvc', ['ngRoute']) .config(function ($routeProvider) { 'use strict'; var routeConfig = { controller: 'TodoCtrl', templateUrl: 'todomvc-index.html', resolve: { store: function (todoStorage) { // Get the correct module (API or localStorage). return todoStorage.then(function (module) { module.get(); // Fetch the todo records in the background. return module; }); } } }; $routeProvider .when('/', routeConfig) .when('/:status', routeConfig) .otherwise({ redirectTo: '/' }); });