AngularJSの学習--TodoMVCの分析
52423 ワード
最近AngularJSを見ていて、少しの時間にまとめてみました.
公式サイトアドレス:http://angularjs.org/
まずいくつかのチュートリアルをお勧めします
1.AngularJS入門チュートリアルは基礎を比較し、公式Tutorialの翻訳である.
2.七歩AngularJS菜鳥から専門家へも基礎を比較し、オンライン音楽再生サイトを作成した.
3.AngularJS開発ガイドこのチュートリアルは全面的ですが、翻訳が少し難解だと思います.
これらのチュートリアルを見て、AngularJSも少し分かったと思ったら、それを使って何かしたいと思って、AngularJSが書いたtodomvcを分析しましょう.
Todomvc公式サイトアドレス:http://todomvc.com/
プロジェクトのディレクトリは次のとおりです.
bower_componentsには2つのフォルダがあり、angularフォルダはangularのように使用されています.jsファイルの、todomvc-commonフォルダには、すべてのtodoプロジェクトが統一されたcssjs(左側のコンテンツを生成するために使用されるだけで、プロジェクトに関係なく)と画像が入っています.
jsフォルダはヘッダで、対応するコントローラ(コントローラ)directive(コマンド)service(サービス)とappが入っています.js.
testフォルダにはテスト用のコードが入っていて、分析しません.
index.htmlはプロジェクトのviewページです.
まずappを見てみましょう.js
モジュールtodomvcを定義します
サービスの下のtodoStorageをもう一度見てください.js
factoryメソッドを使用してtodoStorageのサービスメソッドを作成しました.このサービスメソッドの本質は、2つのメソッドgetとputを返し、どちらもJSON 2とHTML 5の特性を使用しています.getはtodosの内容をlocalStorageから取り出してJSONに解析し、putはtodosをJSON文字列に変換してlocalStorageに格納する.
directivesの下にある2つのコマンドファイルを見てみましょう.
todoFocus.js
functionを返すパラメータでは、elemはその命令を含む要素の配列であり、attrsは要素のすべての属性、属性名などからなるオブジェクトである.
その中で2つのAngularJSの方法が使われています
$watch(watchExpression,listener,objectEquality)は、watchExpressionが変化するたびにリスニングコールバックが実行されるリスナーコールバックを登録します.
$timeout(fn[,delay],,invokeApply])timeoutの値が達するとfn関数が実行されます.
todoFocus.jsはtodoFocus命令を作成した.1つの要素がtodoFocus属性を持つ場合、この命令は要素のtodoFocus属性の値にリスニングを追加し、todoFocus属性の値がtrueに変更されると$timeout(function(){elem[0].focus()}を実行します.0, false);遅延時間は0秒であるため、elem[0]が直ちに実行する.focus().
todoEscape.js
todoEscape.jsはtodoEscape命令を作成した.Escapeキーを押すとattrsが実行する.todoEscapeの式.
ヘッダーを見て、controllersフォルダのtodoCtrl.js、このファイルは少し長いので、私は直接注釈を書きました.
最後にindexを見てみましょう.html、このファイルは私たちが分析しています.
まず一番下に、対応するJSを導入しますが、これはあまり言いません.
style[ng-cloak]を定義し、ng-cloakプロパティを含むと表示されません.
todoを追加するhtmlを見て、バインドするmodelはnewTodoで、submitの方法はtodoCtrlです.jsのaddTodo()は、todoが追加され、Enterをクリックすると、デフォルトでコミットイベントがトリガーされ、addTodo()メソッドがトリガーされ、todosにtodoが追加されます.
todosのhtmlを見せて
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は2つのclassをバインドし、todo.completed、editing:todo==editedTodo、todo.completedはtrueで、completed classを追加し、todo=editedTodoの場合、editing classを追加します.classはtoggleのcheckboxにtodoにバインドされます.completed.todoタイトルに表示されるlabelはダブルクリックイベントをバインドし、ダブルクリックしてeditTodo(todo)をトリガーし、editTodoはeditedTodoにtodoを割り当て、次のformのtodoFocusコマンドをトリガーします.formのinputが表示されます.Escを押すとrevertEditing(todo)がトリガーされ、編集前に戻り、Enterを押すかフォーカスを失うとdoneEditing(todo)がトリガーされ、編集後のtodoが保存されます.classはdestroyのbuttonにclickイベントをバインドし、removeTodo(todo)をクリックしてtodoを削除します.
最後にtodosの統計表示のhtmlを見て
ng-pluralizeラベルはremainingCount個数が1の場合item leftを表示し、そうでない場合items leftを表示することを実現した.
idがfiltersであるulタグにはlocation.path()の内容が異なり、タグの異なるaラベルが選択されます.
idはclear-completedのbuttonにクリックイベントを追加し、clearCompletedTodos()をトリガーし、完了したtodoをすべてクリアします.
分析はこれで终わります.间违いがあったり、分からないところがあったりしたら、伝言を残してください.
公式サイトアドレス:http://angularjs.org/
まずいくつかのチュートリアルをお勧めします
1.AngularJS入門チュートリアルは基礎を比較し、公式Tutorialの翻訳である.
2.七歩AngularJS菜鳥から専門家へも基礎を比較し、オンライン音楽再生サイトを作成した.
3.AngularJS開発ガイドこのチュートリアルは全面的ですが、翻訳が少し難解だと思います.
これらのチュートリアルを見て、AngularJSも少し分かったと思ったら、それを使って何かしたいと思って、AngularJSが書いたtodomvcを分析しましょう.
Todomvc公式サイトアドレス:http://todomvc.com/
プロジェクトのディレクトリは次のとおりです.
bower_componentsには2つのフォルダがあり、angularフォルダはangularのように使用されています.jsファイルの、todomvc-commonフォルダには、すべてのtodoプロジェクトが統一されたcssjs(左側のコンテンツを生成するために使用されるだけで、プロジェクトに関係なく)と画像が入っています.
jsフォルダはヘッダで、対応するコントローラ(コントローラ)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を定義します
サービスの下の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のサービスメソッドを作成しました.このサービスメソッドの本質は、2つのメソッドgetとputを返し、どちらもJSON 2とHTML 5の特性を使用しています.getはtodosの内容をlocalStorageから取り出してJSONに解析し、putはtodosをJSON文字列に変換してlocalStorageに格納する.
directivesの下にある2つのコマンドファイルを見てみましょう.
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は要素のすべての属性、属性名などからなるオブジェクトである.
その中で2つのAngularJSの方法が使われています
$watch(watchExpression,listener,objectEquality)は、watchExpressionが変化するたびにリスニングコールバックが実行されるリスナーコールバックを登録します.
$timeout(fn[,delay],,invokeApply])timeoutの値が達するとfn関数が実行されます.
todoFocus.jsはtodoFocus命令を作成した.1つの要素が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()メソッドがトリガーされ、todosにtodoが追加されます.
<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は2つのclassをバインドし、todo.completed、editing:todo==editedTodo、todo.completedはtrueで、completed classを追加し、todo=editedTodoの場合、editing classを追加します.classはtoggleのcheckboxにtodoにバインドされます.completed.todoタイトルに表示されるlabelはダブルクリックイベントをバインドし、ダブルクリックしてeditTodo(todo)をトリガーし、editTodoはeditedTodoにtodoを割り当て、次の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をすべてクリアします.
分析はこれで终わります.间违いがあったり、分からないところがあったりしたら、伝言を残してください.