Home  >  Article  >  Web Front-end  >  Analysis of TodoMVC in AngularJS Study Notes_AngularJS

Analysis of TodoMVC in AngularJS Study Notes_AngularJS

WBOY
WBOYOriginal
2016-05-16 16:13:261447browse

I have been looking at AngularJS recently, so I will take a moment to summarize it.

Official website address: http://angularjs.org/

Recommend a few tutorials first

1. AngularJS Getting Started Tutorial It is relatively basic and is the translation of the official Tutorial.

2. From AngularJS novice to expert in seven steps. It is also relatively basic and I created an online music playing website.

3. AngularJS Development Guide This tutorial is relatively comprehensive, but I feel that the translation is a bit obscure.

After reading these tutorials, I feel that I understand AngularJS a little bit, and I want to use it to do something. Let’s analyze todomvc written in AngularJS.

Todomvc official website address: http://todomvc.com/

The directory of the project is as follows:

There are two folders placed in bower_components. The angular folder is used to store the angular.js file. The todomvc-common folder contains the unified cssjs for all todo projects (only used to generate the left side content, not related to the project) and pictures.

The js folder is the big header, which contains the corresponding controller (controller) directive (instruction) service (service) and app.js.

The test folder contains code for testing and will not be analyzed.

index.html is the view page of the project.

Let’s take a look at app.js first

Copy code The code is as follows:

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

It defines a module todomvc

Take another look at todoStorage.js under services

Copy code The code is as follows:

/*global todomvc */
'use strict';
/**
 * Services that persists and retrieves TODOs from localStorage
 */
todomvc.factory('todoStorage', function () {
// The unique identifier of todos JSON string storage
var STORAGE_ID = 'todos-angularjs';
Return {
​​​​ // Get todos from localStorage and parse it into a JSON object
          get: function () {
                return JSON.parse(localStorage.getItem(STORAGE_ID) || '[]');
},
// Convert the todos object into a JSON string and store it in localStorage
Put: function (todos) {
​​​​​​localStorage.setItem(STORAGE_ID, JSON.stringify(todos));
}
};
});

The service method of todoStorage is created using the factory method. The essence of this service method is to return two methods, get and put, both of which use the features of JSON2 and HTML5. get takes the content of todos from localStorage and parses it into JSON, and put converts todos into a JSON string and stores it in localStorage.

Look at the two instruction files under directives again.

todoFocus.js

Copy code The code is as follows:

/*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) {
​​​​ // Add a listener for the value of the todoFocus attribute
scope.$watch(attrs.todoFocus, function (newVal) {
                if (newVal) {
                    $timeout(function () {
                      elem[0].focus();
                 }, 0, false);
            }
        });
};
});

Among the parameters returned to function, elem is the array containing the elements of the instruction, and attrs is an object composed of all attributes and attribute names of the element.

Two AngularJS methods are used

$watch(watchExpression, listener, objectEquality) registers a listener callback. Whenever watchExpression changes, the listener callback will be executed.

$timeout(fn[, delay][, invokeApply]) When the value of timeout is reached, execute the fn function.

todoFocus.js creates the todoFocus directive. When an element has a todoFocus attribute, this instruction will add a listener to the value of the element's todoFocus attribute. If the value of the todoFocus attribute changes to true, $timeout(function () {elem[0].focus(); will be executed). }, 0, false); The delay time is 0 seconds, so elem[0].focus() will be executed immediately.

todoEscape.js

Copy code The code is as follows:

/*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 creates the todoEscape directive. When the Escape key is pressed, the attrs.todoEscape expression is executed.

Look at the header, todoCtrl.js in the controllers folder. This file is a bit long, so I just wrote comments.

Copy code The code is as follows:

/*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中获取all
    var todos = $scope.todos = todoStorage.get();

// Record new todo
$scope.newTodo = '';
// Record the edited todo
$scope.editedTodo = null;
// Execute the method when the value of todos changes
$scope.$watch('todos', function (newValue, oldValue) {
​​​​ // Get the number of unfinished todos
           $scope.remainingCount = filterFilter(todos, { completed: false }).length;
​​​​ // Get the number of completed todos
           $scope.completedCount = todos.length - $scope.remainingCount;
// If and only if $scope.remainingCount is 0, $scope.allChecked is true
          $scope.allChecked = !$scope.remainingCount;
// When the new value of todos is not equal to the old value, store todos
in localStorage If (newValue !== oldValue) { // This prevents unneeded calls to the local storage
             todoStorage.put(todos);
}
}, true);
If ($location.path() === '') {
​​​​ //If $location.path() is empty, set it to /
          $location.path('/');
}
$scope.location = $location;
// Execute the method when the value of location.path() changes
$scope.$watch('location.path()', function (path) {
​​​​ // Get status filter
// If path is '/active', filter is { completed: false }
// If path is '/completed', filter is { completed: true }
​​​​ // Otherwise, the filter is null
           $scope.statusFilter = (path === '/active') ?
{ completed: false } : (path === '/completed') ?
                      { completed: true } : null;
});
// Add a new todo
$scope.addTodo = function () {
      var newTodo = $scope.newTodo.trim();
If (!newTodo.length) {
             return;
}
​​​​ // Add a todo to todos, the completed attribute defaults to false
         todos.push({
               title: newTodo,
completed: false
        });
                                        // Leave empty
           $scope.newTodo = '';
};
//Edit a todo
$scope.editTodo = function (todo) {
           $scope.editedTodo = todo;
                // Clone the original todo to restore it on demand.
                  // Save the todo before editing to prepare for resuming editing
           $scope.originalTodo = angular.extend({}, todo);
};
// Edit todo completed
$scope.doneEditing = function (todo) {
                                        // Leave empty
          $scope.editedTodo = null;
         todo.title = todo.title.trim();
If (!todo.title) {
                                                // If the todo’s title is empty, remove the todo
               $scope.removeTodo(todo);
}
};
//Restore the todo before editing
$scope.revertEditing = function (todo) {
         todos[todos.indexOf(todo)] = $scope.originalTodo;
          $scope.doneEditing($scope.originalTodo);
};
// Remove todo
$scope.removeTodo = function (todo) {
         todos.splice(todos.indexOf(todo), 1);
};
// Clear completed todos
$scope.clearCompletedTodos = function () {
$scope.todos = todos = todos.filter(function (val) {
               return !val.completed;
        });
};
// Mark the status of all todos (true or false)
$scope.markAll = function (completed) {
         todos.forEach(function (todo) {
              todo.completed = completed;
        });
};
});

Finally, take a look at index.html. Let’s analyze this file section by section.

Copy code The code is as follows:



   
       
       
        AngularJS • TodoMVC
       
       
   
   
       

           
           

               
               
               

                       

  •                        

                               
                               
                               
                           

                           

                               
                           

                       

  •                

           

           

                {{remainingCount}}
                   
               

               

                       

  •                         All
                       

  •                    

  •                         Active
                       

  •                    

  •                         Completed
                       

  •                

               
           

       

       
       
       
       
       
       
       
       
   

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

复制代码 代码如下:








定义style[ng-cloak],含有ng-cloak属性则不可见。

复制代码 代码如下:


来看添加todo的html,绑定的model为newTodo,submit的方法是todoCtrl.js中的addTodo(),会添加一条todo,点击Enter,默认触发提交事件,就触发了addTodo()方法,添加了一条todo到todos中。

复制代码 代码如下:


   

再看展示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绑定了两个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

复制代码 代码如下:


    {{remainingCount}}
       
   

   

           

  •             All
           

  •        

  •             Active
           

  •        

  •             Completed
           

  •    

   

ng-pluralize标签实现了当remainingCount个数为1时,显示 item left,否则显示 items left。

id为filters的ul标签中根据location.path()的内容不同,标记不同的a标签被选中。

id为clear-completed的button添加了点击事件,触发clearCompletedTodos(),清除掉所有已完成的todo。

今天的笔记就先到这里吧,都是些个人心得,希望小伙伴们能够喜欢。

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn