在先前的步骤中,我们看到了一个控制器和一个模板如何一起工作来将一个静态的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.

总结

您已经学会如何组织您的应用和如何将展示层逻辑引入独立可复用的组件中。让我们进入下一步来看看怎样在我们的目录和文件中组织代码,以在应用扩展的情况下,保持代码的易定位性(easy to locate)。

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

  1. [Angular 2] Angular 2 Smart Components vs Presentation Components

    Both Smart Components and Presentation Components receive data from Services in entirely different w ...

  2. [Angular Tutorial]PhoneCat Tutorial App

    (注:曾经在<不敢止步>一书中看到学到一个观点,作者认为学习一门技术最好的方法就是翻译某部领域书籍.这里我决定做一次尝试,接下来花1个月左右时间,将Angular Tutorial Pho ...

  3. Angular 2 to Angular 4 with Angular Material UI Components

    Download Source - 955.2 KB Content Part 1: Angular2 Setup in Visual Studio 2017, Basic CRUD applicat ...

  4. [Angular Tutorial] 4 - Directory and File Organization

    在这一步中,我们将不会在我们的应用中添加任何新功能,相反,我们打算退回一步,重构我们的代码库,移动我们的代码和文件,以此来使我们的应用更具易扩展性和可维护性. 在先前的步骤中,我们已经见识到了如何将我 ...

  5. [Angular Tutorial] 7-XHRs & Dependency Injection

    我们受够了在应用中用硬编码的方法嵌入三部电话!现在让我们用Angular内建的叫做$http的服务来从我们的服务器获取更大的数据集吧.我们将会使用Angular的依赖注入来为PhoneListCtrl ...

  6. [Angular Tutorial] 6-Two-way Data Binding

    在这一步中,您将会添加一个新特性来使得您的用户可以控制电话列表中电话的顺序,动态改变顺序是由创建一个新的数据模型的特性实现的,将它和迭代器绑定在一起,并且让数据绑定神奇地处理下面的工作. ·除了搜索框 ...

  7. [Angular Tutorial] 0-Bootstraping

    在这一节的tutorial中,您将会逐渐熟悉AngularJS phonecat app的最重要的源代码文件.您也将学到如何将开发服务器与angular-seed绑定到一起,并且在浏览器中运行应用. ...

  8. [Angular] Communicate Between Components Using Angular Dependency Injection

    Allow more than one child component of the same type. Allow child components to be placed within the ...

  9. [Angular Tutorial] 14 -Animations

    在这一步中,我们将会通过在我们先前创建的模板代码中添加CSS和JavaScript动画效果来扩展我们的web应用. ·我们现在使用ngAnimate模块来允许动画效果贯穿整个应用. ·我们也依赖于自带 ...

随机推荐

  1. Windows API 之 CreateFile、CreateFileMapping 、MapViewOfFile

    CreateFile Creates or opens a file or I/O device. The most commonly used I/O devices are as follows: ...

  2. ViewPager+Fragment,Fragment会预加载的问题

    http://www.bubuko.com/infodetail-535920.html 在Fragmetn里,onCreateView去加载布局,真正的加载数据通过这个方法setUserVisibl ...

  3. hdu_2544_最短路(spfa版子)

    题目连接:hdu_2544_最短路 存个自己写的SPFA的板子 #include<cstdio> #include<cstring> #define mst(a,b) mems ...

  4. WiresShark 一站式学习

    按照国际惯例,从最基本的说起. 抓取报文: 下载和安装好Wireshark之后,启动Wireshark并且在接口列表中选择接口名,然后开始在此接口上抓包.例如,如果想要在无线网络上抓取流量,点击无线接 ...

  5. jQuery常用及基础知识总结(二)

    JQuery Effects 方法说明 show( ) 显示隐藏的匹配元素.show( speed, [callback] ) 以优雅的动画显示所有匹配的元素,并在显示完成后可选地触发一个回调函数.h ...

  6. css设置层级显示

    效果: 代码: <li id="tabIdcontent4" class="nomal" tabid="content4" style ...

  7. Object.wait()与Object.notify()的用法

    http://www.cnblogs.com/xwdreamer/archive/2012/05/12/2496843.html 参考文献: object.wait()和object.notify() ...

  8. ARM指令集学习总结-转载

    ARM指令集比较简单,本文介绍ARM指令集中需要注意和不易理解的地方.       一.ARM指令集是32位的,程序的启动都是从ARM指令集开始,包括所有异常中断都是自动转化为ARM状态,并且所有的指 ...

  9. Mybatis的<where><foreach><set>等标签详解

    sql语句where条件中,需要一些安全判断,例如按性别检索,如果传入的参数是空的,此时查询出的结果很可能是空的,也许我们需要参数为空 时,是查出全部的信息.这是我们可以使用动态sql,增加一个判断, ...

  10. 一道js题

    <script> var a = 5; function test(){ this.a = 10; a = 15 this.func = function(){ var a = 20 ; ...