文章来源:http://www.cnblogs.com/CraryPrimitiveMan/p/3499131.html
项目资料来源:http://todomvc.com/examples/angularjs/#/
工程目录结构如下:
lib文件夹下放有angular.js文件的,common文件夹里的放入了所有todo项目统一的css\js;js文件夹是大头,里面放了相应的controller(控制器)\directive(指令)\service(服务)和app.js;index.html是项目的view页面。
先来看一下app.js,就是定义了一个模块todomvc。
/*global angular */ /*jshint unused:false */ 'use strict'; /** * The main TodoMVC app module * * @type {angular.Module} */ var todomvc = angular.module('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的表达式。
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="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="common/base.js"></script> <script src="lib/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="common/base.js"></script> <script src="lib/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。
运行效果:
相关推荐
Spring Boot 和 AngularJS 中的 Todomvc 演示项目演示如何使用 Spring Boot 构建简单的 REST API。 前端部分取自 基于 Spring Boot 1.2.RC2 AngularJS 待办事项基于简单的HashMap存储在内存存储库中,可以轻松...
通过分析和实践这段代码,我们可以深入理解AngularJS在实际项目中的运用。 在标签中提到了"AngularJS"和"TodoMVC",这意味着我们将重点探讨这两个主题。AngularJS是Google推出的前端框架,它提供了一种声明式编程...
AngularJS TodoMVC 示例 + iFrame 测试观看现场这是 TodoMvc 存储库中的 Angularjs 示例的一个分支, 。 function testTodos ( api ) { api . removeAll ( ) . then ( delay ) . then ( function ( ) { api . add ( ...
React 是一个用于构建用户界面的 JAVASCRIPT 库。 React 主要用于构建UI,很多人认为 React 是 MVC 中的 V(视图)。 React 起源于 Facebook 的内部项目,用来架设 Instagram 的网站,并于 2013 年 5 月开源。...
在本文中,我们将深入探讨如何使用Vue.js框架来实现经典的TodoMVC应用。Vue.js是一个轻量级的前端JavaScript框架,以其易用性、灵活性和强大的功能而受到开发者们的广泛欢迎。通过构建TodoMVC,我们可以熟悉Vue的...
【标题】"todomvc-angularjs-sailsjs"是一个基于AngularJS和ExpressJS的TodoMVC实现项目,它展示了如何使用这两个流行的JavaScript框架构建一个功能完备的Web应用程序。TodoMVC是一个用来比较不同前端框架实现的简单...
在"marionettejs实现todoMVC(更新版)"这个项目中,我们将看到如何利用MarionetteJS来重构经典的TodoMVC应用,优化statusview的显示和关闭机制。 TodoMVC是一个被广泛使用的示例应用,用于演示不同MV*框架或库如何...
TodoMVC旨在用各种框架实现TodoList的增、删、改、查功能,麻雀虽小,五脏俱全,是供小伙伴学习、练习、再学习的好例子。 虽然官网上有各种实现版本,但仿佛缺少那么一个版本,就是,就是。。。我实现的版本。为此,...
mobx-react-todomvc, 在响应mobX样板的基础上,TodoMVC参考实现 响应 MobX TodoMVC示例这个库提供了使用 MobX插件编写的 TodoMVC应用程序的参考实现, 响应插件,JSX和 ES6.运行示例npm installnpm startopen ...
在本文中,我们将深入探讨如何使用Vue.js框架来构建一个TodoMVC应用,这是一个非常经典的JavaScript应用程序示例,常用于展示MVVM(Model-View-ViewModel)架构的基本原理。Vue.js是一个轻量级且功能强大的前端框架...
1. **阅读和理解代码**:逐行分析模板中的代码,了解每个部分的作用。 2. **动手实践**:尝试修改模板,添加新功能,如过滤已完成的任务、本地存储待办事项等。 3. **扩展知识**:学习更多Vue.js高级特性,如组件...
在本文中,我们将深入探讨如何使用React和Meteor框架构建一个实时的Web应用,以此实现一个与众不同的Todomvc。Todomvc是一个经典的示例项目,它展示了多种前端框架的使用方式,而在这个案例中,我们将利用React的...
TodoMVC是一个经典的示例项目,用于演示各种MV*框架(Model-View-Controller或其变体)如何处理基本的待办事项管理任务。在这个项目中,我们将深入探讨MarionetteJS如何通过其核心概念来实现TodoMVC。 1. **...
TodoMVC支持多种JavaScript框架和库,如AngularJS、React、Ember.js等。每个框架的实现都有其独特的编程风格和理念,通过对比不同框架的TodoMVC实现,开发者可以了解它们的优点和缺点。 **5. 开发过程** - **模型...
"todomvc"是学习和展示MVC(Model-View-Controller)架构模式的一个经典案例,适用于各种前端框架,包括Vue。在“vue第2天-todomvc案例”中,我们将深入探讨如何使用Vue.js实现一个基本的待办事项管理应用。 首先,...
2. **纯JavaScript**:在这个示例中,我们将不使用jQuery、AngularJS、React等库,而是直接使用JavaScript原生API来构建应用,这将帮助我们更好地理解JavaScript的事件处理、DOM操作和数据管理。 **二、项目结构** ...
Create React App入门该项目是通过引导的。可用脚本在项目目录中,可以运行:yarn start 在开发模式下运行该应用程序。 打开在浏览器中查看它。 如果您进行编辑,则页面将重新加载。 您还将在控制台中看到任何棉绒...