`
2008winstar
  • 浏览: 57728 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论
  • chenke: 写的很好,也可以看看那这个文章,我感觉学的还可以。http:/ ...
    HTML

AngularJS 教程

 
阅读更多

本文翻译自这里

翻译过程中加入了译者本人的理解,并作了适当的筛减。

 

简介

创建一个简单的邮件应用程序,学习核心的AngularJS概念。在结束该教程的学习时,你将能够看到(虚构的)邮件应用程序,在该程序中,可以根据邮件主题查询邮件,还可以阅读或删除邮件。

 

学习的先决条件:

  • 会使用jQuery创建简单的JavaScript应用
  • 懂得如何启动简单的HTTP服务器(如 python -m SimpleHTTPServer)
  • 会从Github上克隆一个项目

涵盖的主题

  • 单页面应用(SPA)
  • 客户端MVC模式
  • 双向数据绑定
  • 路由与模板
  • AngularJS构建块:指令标签(Directives),工厂(Factories)以及控制器(Controllers)

客户端MVC

  • 模型(Model):可以说是数据;一个应用的业务信息;
  • 视图(View):HTML和数据的呈现。是用户所见到和交互的界面;
  • 控制器(Controller):让应用中的所有不同模块协同工作的连接器。

开始使用AngularJS

在页面中引入AngularJS

在HTML页面的底部<body>结束标签之前引入AngularJS的.js文件。

<html>
    <head>
    </head>
    <body>
        <div></div>
        <script src="lib/jquery-v1.11.1.js"></script>
        <script src="lib/angular-v1.2.22.js"></script>
    </body>
</html>

 

Angular自身内置了一个叫做“jQLite”的东西,它是一个类似jQuery的微型库。jQLite是一个非常轻量级的库,因此也就没有你可能需要的强大的jQuery方法。这里引入jQuery主要是出于可能后续会引入一些依赖于jQuery库的插件。

 

设置作用域(Scopes)和指令标签(Directives)

Angular非常基础的一个概念是作用域(scopes)。Scopes保存着你的Models(也就是你的数据),它与你的控制器(Controllers)一起协作,同时为视图(Views)提供了所需的一切。Angular的scopes概念与常见的JavaScript中的作用域(scope)概念非常相似。

 

第一步是需要设置整个应用的作用域,它标识出了Angular应用起作用的范围。通常我们会在<html>标签中通过ng-app属性来设置它。

<html ng-app="myApp">
    <head></head>
    <body></body>
</html>

 

另外一个与scope相关的指令是ng-controller,它决定了一个控制器的作用域范围。在一个应用中可以包含多个控制器。每个控制器都有其自身的作用域范围。

<div ng-controller="InboxCtrl">
    <!-- inside InboxCtrl scope -->
</div>

 

ng-app和ng-controller都是Angular指令标签。可以把Angular指令标签看作是对HTML的扩展。

 

你的第一个控制器:一个简单的例子

把我们刚刚学到的用在实践中

1 创建一个空的HTML文档

2 引入Angular和jQuery文件

<script src="lib/jquery-v1.11.1.js"></script>
<script src="lib/angular-v1.2.22.js"><script>

 

3 在<html>标签中添加ng-app="myApp"

4 在body中创建一个控制器示例

<div ng-controller="TestCtrl"><h1></h1>
   <input type="text" ng-model="title">
</div>

    稍后我们会解释ng-model="title"的含义。

5 创建内嵌的JavaScript脚本,确保该脚本在所引用库文件之后。

<script>
   function TestCtrl($scope) {
      $scope.title = 'Write a title here...';
   };
</script>

    是否已发现函数的名字跟ng-controller的值是一样的?Angular会在JavaScript中寻找相同名称的函数来作为控制器。

 

以下是完整的代码:

<!doctype html>
<html ng-app>
  <head>
    <title>Sample AngularJS Controller</title>
  </head>
  <body>
    <div ng-controller="TestCtrl">
        <h1></h1>
        <input type="text" ng-model="title">
    </div>

    <script src="lib/jquery-v1.11.1.js"></script>
    <script src="lib/angular-v1.2.22.js"></script>

    <script>
      function TestCtrl($scope) {
        $scope.title = 'Write a title here...';
      };
    </script>
  </body>
</html>

 

ngView与路由(Routes)

将URL与作用域关联

另外一个重要的构建块是ng-view指令标签,它能够将应用中的某个URL关联到作用域中。

<html ng-app="myApp">
    <head>
    </head>
    <body>
        <div ng-view></div>
    </body>
</html>

 

这里的ng-view标签能够根据用户访问的URL告诉Angular我们想插入的HTML。

 

模块(Modules)

angular.module()

每个应用需要一个模块,而Angular通过angular.module()为我们提供了模块命名空间的能力。该方法既可以设置模块也可以获取一个模块,关键取决于如何使用它。创建(设置)一个新的模块,如:

angular.module('myApp', []);

 

获取一个模块的引用,用以注册controllers,factories,filters等,可以不用后面的那个数组而只需通过模块的名称:

angular.module('myApp');

 

路由(Routing)与依赖注入(Dependency Injection)

路由

接下来是配置路由,路由使应用能够根据我们访问的URL来确定加载哪个视图。

RouteProvider

从Angular 1.2.0版本开始,核心的Angular中不在包含$routeProvider,因此需要将其作为一个独立的模块引入(angular-route.js)。

<body>
    <!-- ... -->
    <!-- Extra routing library -->
    <script src="lib/angular-route-v1.2.22.js"></script>
</body>

 

该文件为我们提供了一个名为ngRoute的模块,在我们自己的模块定义的时候需要将其作为依赖引入:

var app = angular.module('app', [
   'ngRoute'
]);

 

配置阶段

Angular中每个模块具有一个.config()方法,可以给该方法传入一个回调函数,该回调函数将在很多其他函数执行前调用。就是在这个地方配置我们的路由:

app.config(function () {/*...*/});

 

依赖注入

在config回调函数中,我们需要$routeProvider来配置路由,可以简单地把$routeProvider作为config函数的参数传入,剩下的事情交由Angular处理。

app.config(function ($routeProvider) {
   /* Now we can use the routeProvider! :D */
});

 

配置路由

app.config(function ($routeProvider) {
   $routeProvider
      .when('/inbox', {
         templateUrl: 'views/inbox.html',
         controller: 'InboxCtrl',
         controllerAs: 'inbox'
      })
      .when('/inbox/email/:id', {
         templateUrl: 'views/email.html',
         controller: 'EmailCtrl',
         controllerAs: 'email'
      })
      .otherwise({
         redirectTo: '/inbox'
      });
});

 

控制器(Controllers)

连接模型与视图

一个好的控制器只包含尽可能少的逻辑在里面,且只完成两项工作:将模型绑定到视图(初始化视图);为视图添加帮助函数。

app.controller('InboxCtrl', function () {
   // Model and View bindings
   // Small helper function not needed anywhere else
});

 

每个控制器都能够访问$scope。通过$scope可以往视图上添加属性和方法。

app.controller('InboxCtrl', function ($scope) {
   // initialize the title property to an array for the view to use
   $scope.title = "This is a title";
});

 

在标签中可以这样与之对应:

<div ng-controller="InboxCtrl">
   {{ title }}
</div>

 

工厂(Factories)

工厂常用于通过HTTP与服务端交互。

可以通过angular.factory()方法创建一个工厂,如:

app.factory('ExampleFactory', function ExampleFactory($rootScope, $http, $location) {
   return function myReusableFunction() {
      // do something fancy
   };
});

 

在该应用中,需要获取邮件信息,可以创建一个方法来实现。Angular使用$http服务来与服务端交互,因此需要将它也引入:

app.factory('InboxFactory', function InboxFactory ($http) {
   var exports = {};

   exports.getMessages = function () {
      return $http.get('json/emails.json')
         .error(function (data) {
            console.log('There was an error!', data);
      });
   };

   return exports;
});

 

关联工厂与控制器

app.controller('InboxCtrl', function($scope, InboxFactory) {
   InboxFactory.getMessages()
      .success(function(jsonData, statusCode) {
         console.log('The request was successful!', statusCode, jsonData);
         // Now add the Email messages to the controller's scope
         $scope.emails = jsonData;
   });
});

 

模板(Templating)

视图渲染

<!-- JavaScript inside expression -->
<h1>{{ [ firstName, lastName ].join(" ") }}</h1>
<!-- currency filter applied to a multiplication of 2 numbers -->
<div class="total-info">{{ cost * quantity | currency }}</div>
<!-- Using a ternary expression inside the expression -->
<div class="budget">{{ ( total > budget ) ? "Too Expensive" : "You can buy it!" }}</div>

 

指令标签概览

自定义HTML标签

指令标签是Angular提供的自定义HTML标签,它为封装数据、模板与行为提供了一种可重用的方式。

在我们的视图中,有时可以见到如下的标签:

<div id="someview">
   {{ data.scopePropertyAsUsual }}
   <my-custom-element></my-custom-element>
</div>

 

上面的<my-custom-element>标签会被我们定义的标签模板和逻辑替代。以下为一个简单的指令标签结构示例:

app.directive('myCustomElement', function myCustomElement() {
   return {
      restrict: 'EA',
      replace: true,
      scope: true,
      template: [
         "<div>",
         "	<h1>My Custom Element's Heading</h1>",
         "	<p>Some content here!</p>",
         "	<pre>{{ ctrl.expression | json }}</pre>,"
         "</div>"
      ].join(""),
      controllerAs: 'ctrl',
      controller: function ($scope) {
         this.expression = {
            property: "Example"
         }
      },
      link: function (scope, element, attrs) {}
   }
});

 

工厂与指令协同工作

angular.module('EmailApp')
   .factory('InboxFactory', function InboxFactory ($q, $http, $location) {
      'use strict';
      var exports = {};

      exports.messages = [];

      exports.goToMessage = function(id) {
         if ( angular.isNumber(id) ) {
            // $location.path('inbox/email/' + id)
         }
      }

      exports.deleteMessage = function (id, index) {
         this.messages.splice(index, 1);
      }

      exports.getMessages = function () {
         var deferred = $q.defer();
         return $http.get('json/emails.json')
            .success(function (data) {
               exports.messages = data;
               deferred.resolve(data);
            })
            .error(function (data) {
               deferred.reject(data);
            });
         return deferred.promise;
      };

      return exports;
   });

 

app.directive('inbox', function () {
   return {
      restrict: 'E',
      replace: true,
      scope: true,
      templateUrl: "js/directives/inbox.tmpl.html",
      controllerAs: 'inbox',
      controller: function (InboxFactory) {
         this.messages = [];
         this.goToMessage = function (id) {
            InboxFactory.goToMessage(id);
         };
         this.deleteMessage = function (id, index) {
            InboxFactory.deleteMessage(id, index);
         };
         InboxFactory.getMessages()
            .then( angular.bind( this, function then() {
               this.messages = InboxFactory.messages;
            })	);
      },
      link: function (scope, element, attrs, ctrl) {
         /*
         by convention we do not $ prefix arguments to the link function
         this is to be explicit that they have a fixed order
         */
      }
   }
});

 

用于上述指令标签的完整HTML模板:

 

<div class="inbox">
  <div class="inbox__count">
    You have {{ inbox.messages.length && inbox.messages.length || 'no' }} messages
  </div>
  <div ng-hide="!inbox.messages.length">
    <input type="text" class="inbox__search" 
      ng-model="inbox.search" 
      placeholder="Search by 'from', e.g. TicketMaster">
  </div>
  <ul class="inbox__list">
    <li ng-show="!inbox.messages.length">
      No messages! Try sending one to a friend.
    </li>
    <li ng-repeat="message in inbox.messages | filter:{ from: inbox.search }">
      <div class="inbox__list-info">
        <p class="inbox__list-from"> from: {{ message.from }} </p>
        <p class="inbox__list-date"> {{ message.date | date: 'dd/MM/yyyy' }} </p>
        <p class="inbox__list-subject"> {{ message.subject }} </p>
      </div>
      <div class="inbox__list-actions">
        <a href="#" ng-click="inbox.goToMessage(message.id);">
          Read
        </a>
        <a href="" ng-click="inbox.deleteMessage(id, $index);">
          Delete
        </a>
      </div>
    </li>
  </ul>
</div>

 

内置指令标签

ng-show, ng-repeat, ng-click

 

<ul>
   <li ng-repeat="item in items">
      {{ item.name }}
   </li>
</ul>

 

 

<li ng-repeat="message in inbox.messages | filter:{ from: inbox.search }">

 

 

<input type="text" class="inbox__search" placeholder="Search" ng-model="inbox.search">

 

 

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics