[Angular Tutorial] 3-Components

在先前的步骤中,我们看到了一个控制器和一个模板如何一起工作来将一个静态的HTML文件转化为动态页面(view)。一般说来,这在单页应用中一种非常常见的模式(在Angular应用中尤其是这样):

  ·客户端代码“掌管”并和视图层实现了动态交互,通过在数据模型和状态中即刻更新视图来反应改变,这经常是用户交互的结果(我们不久将在第5步中看到一个例子),这种做法取代了在服务端创建一个静态HTML页面的做法。

模板(视图层包含绑定和展示逻辑的部分)作为一个蓝图,以此来决定我们数据怎么组织和展示给用户。而控制器提供了执行绑定和在我们的模板中申请行为和逻辑的环境(context)。

应用中依然有几个可以做得更好的地方:

  1.要是我们想在我们应用的不同部分复用相同的功能,怎么做呢?

  我们可能得复制整个模板(包括控制器)。这样做容易出错并且会降低可维护性。

  2.作用域,这被用于将我们的控制器和模板粘合到一起形成一个动态页面,不是从页面的其他部分中分离出来的。这意味着在我们的视图层中,页面不同部分的一个随机,不相关的改变可能导致不可预料且很难debug的副作用。

  (好吧,可能对于我们这小小的范例不用关心这些,但当面临一个更大,真正的应用时这些考虑是合理的。)

  这一步中最大的不同将会在下面列出。您也可以点击这里在GitHub上查看全部的不同。

组件救援!

既然这种组合(模板+控制器)是如此公共和常见的模式,Angular提供了一种简单且优雅的方式来将它们组合成可复用且独立的实体,这被称为组件。另外,Angular为我们组件中的每一个实体创建了一个所谓的isolate作用域,这意味着应用中不再有原型继承,并且我们的组件不会影响应用中的其他部分,反之亦然。

(由于这是一份介绍性的tutorial,我们不会深入介绍Angular 组件的所有特性。您可以通过阅读开发者手册的组件部分来进一步了解组件及其使用模式。

实际上,一种观点认为组件其孪生兄弟的武断(opinionated),精简的(stripped-down)版本,这个孪生兄弟更为复杂和冗余(但确实很有效)--指令,这是用Angular的方式来教会HTML的新把戏,你可以阅读开发者手册的指令部分

注:指令是一个高级话题,所以您可能得延迟学习它们知道您精通了基础部分。)

我们使用Angular模块中的.component()方法来创建一个组件。我们必须提供组件的名字和组件定义对象(Component Definition Object,缩写为CDO)。

请牢记(这点组件和指令一样)组件的名字使用驼峰命名(camelCase),但在我们的HTML中引用它的时候将会使用串联命名法(kebab-case)。

用最简单的形式,CDO将会仅仅包含一个模板和一个控制器。(我们甚至可以省略控制器,Angular会为我们创建一个傀儡控制器,这对于简单的“展示用的”组件是可以的,那将不对模板附加任何行为。)

来看个例子吧:

angular.
  module(‘myApp‘).
  component(‘greetUser‘, {
    template: ‘Hello, {{$ctrl.user}}!‘,
    controller: function GreetUserController() {
      this.user = ‘world‘;
    }
  });

现在,每次我们在视图层引入<greet-user></greet-user> ,Angular将会使用提供的模板将其扩展成一棵DOM字数并且通过制定的控制器实体来管理它。

不过等等,这个$ctrl是哪来的?它又指向哪里?

由于一些已经提及的理由(还有一些已经超出本tutorial范围的理由),避免直接使用作用域(scope)被认为是一次最佳实践。我们可以(而且应该)使用我们的控制器实体;比如将我们的数据和方法分配到我们控制器中(这里“this”包含在控制器构造器中),而不是直接分配给控制器。

我们可以通过别名来从模板中引用控制器。这次,解析我们表达式的环境就更为明了了。默认地,组件使用$ctrl作为控制器的别名,但我们可以在需要的时候重载它。

还有更多可选的操作,所以在您的应用中使用.component()之前请确保您查看过API参考手册

使用组件

既然我们已经知道如何创建组件了,让我们用刚刚学习的技能来重构HTML页面吧。

app/index.html:

<html ng-app="phonecatApp">
<head>
  ...
  <script src="bower_components/angular/angular.js"></script>
  <script src="app.js"></script>
  <script src="phone-list.component.js"></script>
</head>
<body>

  <!-- Use a custom component to render a list of phones -->
  <phone-list></phone-list>

</body>
</html>

app/app.js:

// Define the `phonecatApp` module
angular.module(‘phonecatApp‘, []);

app/phone-list.component.js:

// Register `phoneList` component, along with its associated controller and template
angular.
  module(‘phonecatApp‘).
  component(‘phoneList‘, {
    template:
        ‘<ul>‘ +
          ‘<li ng-repeat="phone in $ctrl.phones">‘ +
            ‘<span>{{phone.name}}</span>‘ +
            ‘<p>{{phone.snippet}}</p>‘ +
          ‘</li>‘ +
        ‘</ul>‘,
    controller: function PhoneListController() {
      this.phones = [
        {
          name: ‘Nexus S‘,
          snippet: ‘Fast just got faster with Nexus S.‘
        }, {
          name: ‘Motorola XOOM™ with Wi-Fi‘,
          snippet: ‘The Next, Next Generation tablet.‘
        }, {
          name: ‘MOTOROLA XOOM™‘,
          snippet: ‘The Next, Next Generation tablet.‘
        }
      ];
    }
  });

没错!输出的结果看起来是一样的,但让我们来看看我们收获了什么:

  ·我们的电话列表是可复用的,将 <phone-list></phone-list>放到页面的任何地方都可以获取一个电话列表。

  ·我们的主视图层(index.html)更加干净而且更具声明性了,仅仅通过查看它,我们就知道里边有一个电话列表。我们不用费心去考虑实现细节。

  ·从“外联影响(external influence)”看来,我们的组件是独立且安全的。同样的,我们不必担心意外地破坏了应用中的其他部分。我们组件中发生的故事依然待在我们的组件内。

  ·独立测试我们的组件变得更容易了。

关于文件命名的一点注解:

通过文件名前缀来区分不同类型的实体是一个好的实践。在这个tutorial中,我们使用.component前缀来表示组件,所以定义某个组件的名字会被命名为some-component.component.js.

时间: 2024-10-19 22:41:01

[Angular Tutorial] 3-Components的相关文章

[Angular 2] Angular 2 Smart Components vs Presentation Components

Both Smart Components and Presentation Components receive data from Services in entirely different ways. Smart Components use constructor injection to lookup the entire service from the injector while Angular 2 Presentation components take the data f

[Angular Tutorial]Turorial

(注:我曾经在<不敢止步>一书中看到,作者认为学习一门技术最好的方法就是翻译某部领域书籍,我决定做一次尝试,接下来花1个月左右时间,将Angular Tutorial中的Phonecat范例全部翻译一遍,这当然更多是希望自己能得到一个提高,尽力做到最好,当然质量难以保证,所有专有名词尽量不译,所有章节与https://docs.angularjs.org/tutorial/对应,如果可以,希望您能对照两边学习,给我提些意见.那么,开始吧!) 本节翻译自:https://docs.angular

[Angular Tutorial] 0-Bootstraping

在这一节的tutorial中,您将会逐渐熟悉AngularJS phonecat app的最重要的源代码文件.您也将学到如何将开发服务器与angular-seed绑定到一起,并且在浏览器中运行应用. 在您继续之前,请确保您已经搭建好您的开发环境并且安装了所有必要的依赖,像这里描述的那样. 在angular-phonecat目录下,运行这条指令: git checkout -f step-0 这将使您工作空间的tutorial app重置到step 0.(注:强烈推荐使用sourcetree,可以

[Angular Tutorial] 4 - Directory and File Organization

在这一步中,我们将不会在我们的应用中添加任何新功能,相反,我们打算退回一步,重构我们的代码库,移动我们的代码和文件,以此来使我们的应用更具易扩展性和可维护性. 在先前的步骤中,我们已经见识到了如何将我们的应用构建得更具模块性和可测试性.另一种同样重要的思想是,用一种使得查看代码变得容易(无论对我们还是团队中的其他开发者)和能在我们应用中快速指定的某区域的相关代码块的方式来组织我们的代码库. 为此,下面我们将解释为何及如何: ·将每一个实体置于他们自己的文件中(own file). ·通过特定区域

[Angular Tutorial] 8 - Templating Links &amp; Images

在这一步中,我们将会在电话列表中为电话添加略图,并附上链接,当然现在也不会链接去哪.在随后的步骤中,我们将使用这些链接来展示电话列表中额外的信息. ·现在电话列表中会有链接和图片. 最重要的不同在下面列出.您可以点击这里在GitHub上查看全部的不同. 数据 注意到phones.json文件中包含了每一部电话的唯一ID和图片URLs.这些URLs指向app/img/phones/目录. app/phones/phones.json (样本代码片段): [ { ... "id": &qu

[Angular Tutorial] 3-Filtering Repeaters

在上一步中,我们花了很大功夫来布局应用的基础,所以我们现在做点简单点的吧!我们将会添加一个全文本搜索框(没错,这很简单). ·我们的应用现在会有一个搜索框,注意页面中手机列表的改变取决于用户在搜索框键入的内容. 最重要的变化列举如下,当然,你也可以点击这里在GitHub上查看全部的不同. 控制器 我们对控制器不做任何修改. 模板 app/index.html: <div class="container-fluid"> <div class="row&quo

[Angular Tutorial] 13 -REST and Custom Services

在这一步中,我们将会改变我们获取数据的方式. ·我们定义一个代表RESTful客户端的自定义服务.使用这个客户端,我们可以用一种更简单的方法向服务端请求数据,而不用处理更底层的$httpAPI,HTTP方法和URLs. 最重要的变化列举如下,您可以点击这里在GitHub上查看全部的不同. 依赖 RESTful功能由Angular的ngResource模块提供,这是从Angular核心模块中独立出来的. 由于我们使用了Bower来安装客户端的依赖,这一步更新bower.json配置文件来添加新的依

[Angular Tutorial] 10 -More Templating

在这一步中,我们会实现电话细节的视图,这在用户点击列表中的一部电话时被展示. ·当您点击列表中的一部电话时,带有电话特定信息的电话细节页面将被展示. 我们打算使用$http来获取我们的数据,以此来实现电话细节视图,然后刷新phoneDetail组件模板. 最大的不同列举如下,您也可以点击这里从GitHub上看到全部不同. 数据 除了phones.json,app/phones/目录中也包含了每一步电话的JSON文件: app/phones/nexus-s.json: (样本片段) { "addi

[Angular Tutorial] 14 -Animations

在这一步中,我们将会通过在我们先前创建的模板代码中添加CSS和JavaScript动画效果来扩展我们的web应用. ·我们现在使用ngAnimate模块来允许动画效果贯穿整个应用. ·我们也依赖于自带的指令来自动触发动画来进行开发. ·当一个动画效果被发现时,在给定的时间内,它将会和置于元素中的实际DOM操作一同运行(比如:在ngRepeat中插入/删除节点或在ngClass中添加/删除类). 最大的不同列举如下,您可以点击这里在GitHub上查看全部的不同. CSS过渡动画:使ngRepeat