Angular 2 教程

Angular2 是一款开源JavaScript库,由Google维护,用来协助单一页面应用程序运行。

Angular2 是 Angular 1.x 的升级版本,性能上得到显著的提高,能很好的支持 Web 开发组件。

Angular2 发布于2016年9月份,它是基于ES6来开发的。


学习本教程需要的基础知识

学习本教程前,你需要具备基本的前端基础:HTML、CSS、JavaScript。此外你还需要了解 NPM 及 TypeScript。


Angular2.x与Angular1.x 的区别

Angular2.x与Angular1.x 的区别类似 Java 和 JavaScript 或者说是雷锋与雷峰塔的区别,所以在学习Angular2.x时大家需要做好重新学习一门语言的心里准备。


运行条件!

由于目前各种环境(浏览器或 Node)暂不支持ES6的代码,所以需要一些shim和polyfill(IE需要)让ES6写的代码能够转化为ES5形式并可以正常运行在浏览器中。

从上图可以看出在 Es5 浏览器下需要以下模块加载器:

  • systemjs - 通用模块加载器,支持AMD、CommonJS、ES6等各种格式的JS模块加载。

  • es6-module-loader - ES6模块加载器,systemjs会自动加载这个模块。

  • traceur - ES6转码器,将ES6代码转换为当前浏览器支持的ES5代码,systemjs会自动加载 这个模块。


相关参考文档

点我分享笔记


取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

点我查看本站打赏源码!

忘记密码?

如何获取邀请码?

关闭

Angular 2 JavaScript 环境配置

本章节我们为大家介绍如何配置 Angular 2 的执行环境。

本章节使用的是 JavaScript 来创建 Angular 的应用,当然你也可以使用 TypeScript 和 Dart 来创建 Angular 应用 。

本章节使用到的文件目录结构如下所示:


创建配置文件

创建目录

$ mkdir angular-quickstart
$ cd angular-quickstart

载入需要的库

这里我们推荐使用 npm 来作为包的管理工具,如果你还没安装npm或者不了解 npm 可以查看我们的教程:NPM 使用介绍

创建 package.json 文件,代码如下所示:


package.json 文件:

{ "name": "angular2-quickstart", "version": "1.0.0", "scripts": { "start": "npm run lite", "lite": "lite-server" }, "license": "ISC", "dependencies": { "@angular/common": "2.0.0", "@angular/compiler": "2.0.0", "@angular/core": "2.0.0", "@angular/forms": "2.0.0", "@angular/http": "2.0.0", "@angular/platform-browser": "2.0.0", "@angular/platform-browser-dynamic": "2.0.0", "@angular/router": "3.0.0", "@angular/upgrade": "2.0.0", "core-js": "^2.4.1", "reflect-metadata": "^0.1.3", "rxjs": "5.0.0-beta.12", "zone.js": "^0.6.23", "angular2-in-memory-web-api": "0.0.20", "bootstrap": "^3.3.6" }, "devDependencies": { "concurrently": "^2.0.0", "lite-server": "^2.2.0" } }

由于 npm 官网镜像国内访问太慢,这里我使用了淘宝的npm镜像,安装方法如下:

$ npm install -g cnpm --registry=https://registry.npm.taobao.org

执行后我们就可以使用 cnpm 命令来安装模块:

$ cnpm install

执行成功后,angular-quickstart 目录下就会生成一个 node_modules 目录,这里包含了我们这个实例需要的模块。


创建 Angular 组件

组件(Component)是构成 Angular 应用的基础和核心,一个组件包装了一个特定的功能,并且组件之间协同工作以组装成一个完整的应用程序。

一般来说,一个组件就是一个用于控制视图模板的JavaScript类。

接下来我们在 angular-quickstart 创建一个 app 的目录:

$ mkdir app
$ cd app

并添加组件文件 app.component.js ,内容如下:

app.component.js 文件:

(function(app) { app.AppComponent = ng.core.Component({ selector: 'my-app', template: '<h1>我的第一个 Angular 应用</h1>' }) .Class({ constructor: function() {} }); })(window.app || (window.app = {}));

接下来我们来分析下以上代码:

我们通过链式调用全局Angular core命名空间ng.core中的Component和Class方法创建了一个名为AppComponent的可视化组件。

Component方法接受一个包含两个属性的配置对象,Class方法是我们实现组件本身的地方,在Class方法中我们给组件添加属性和方法,它们会绑定到相应的视图和行为。

模块

Angular应用都是模块化的,ES5没有内置的模块化系统,可以使用第三方模块系统,然后我们为应用创建独立的命名空间 app,文件代码可以包裹在 IIFE(立即执行函数表达式)中:

(function(app) {
})(window.app || (window.app = {}));

我们将全局app命名空间对象传入IIFE中,如果不存在就用一个空对象初始化它。

大部分应用文件通过在app命名空间上添加东西来输出代码,我们在app.component.js文件中输出了AppComponent。

app.AppComponent =

Class定义对象

本实例中AppComponent类只有一个空的构造函数:

.Class({
    constructor: function() {}
});

当我们要创建一个是有实际意义的应用时,我们可以使用属性和应用逻辑来扩展这个对象。

Component 定义对象

ng.core.Component()告诉Angular这个类定义对象是一个Angular组件。传递给ng.core.Component()的配置对象有两个字段:selector和template。

ng.core.Component({ selector: 'my-app', template: '<h1>我的第一个 Angular 应用</h1>' })

selector 为一个宿主HTML元素定义了一个简单的CSS选择器my-app。当Angular在宿主HTML中遇到一个my-app元素时它创建并显示一个AppComponent实例。

template 属性容纳着组件的模板。


添加 NgModule

Angular 应用由 Angular 模块组成,该模块包含了 Angular 应用所需要的组件及其他任何东西。

接下来我们创建 app/app.module.js 文件,内容如下:

app.module.js 文件:

(function(app) { app.AppModule = ng.core.NgModule({ imports: [ ng.platformBrowser.BrowserModule ], declarations: [ app.AppComponent ], bootstrap: [ app.AppComponent ] }) .Class({ constructor: function() {} }); })(window.app || (window.app = {}));

启动应用

添加 app/main.js 文件:


app/main.js 文件:

(function(app) { document.addEventListener('DOMContentLoaded', function() { ng.platformBrowserDynamic .platformBrowserDynamic() .bootstrapModule(app.AppModule); }); })(window.app || (window.app = {}));

我们需要两样东西来启动应用:

  • Angular 的 platformBrowserDynamic().bootstrapModule 函数。
  • 上文中提到的应用根模块 AppModule。

接下来创建 index.html,代码如下所示:


index.html 文件:

<html> <head> <meta charset="utf-8"> <title>Angular 2 实例 - 菜鸟教程(runoob.com)</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="styles.css"> <!-- 1. 载入库 --> <!-- IE 需要 polyfill --> <script src="node_modules/core-js/client/shim.min.js"></script> <script src="node_modules/zone.js/dist/zone.js"></script> <script src="node_modules/reflect-metadata/Reflect.js"></script> <script src="node_modules/rxjs/bundles/Rx.js"></script> <script src="node_modules/@angular/core/bundles/core.umd.js"></script> <script src="node_modules/@angular/common/bundles/common.umd.js"></script> <script src="node_modules/@angular/compiler/bundles/compiler.umd.js"></script> <script src="node_modules/@angular/platform-browser/bundles/platform-browser.umd.js"></script> <script src="node_modules/@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js"></script> <!-- 2. 载入 'modules' --> <script src='app/app.component.js'></script> <script src='app/app.module.js'></script> <script src='app/main.js'></script> </head> <!-- 3. 显示应用 --> <body> <my-app>Loading...</my-app> </body> </html>

index.html 分析

  • 1、载入我们需要的JavaScript库;
  • 2、载入我们自己的JavaScript文件,注意顺序;
  • 3、我们在<body>标签中添加<my-app>标签。

执行过程为:当 Angular 在 main.js 中调用 bootstrapModule 函数时,它读取 AppModule 的元数据,在启动组件中找到 AppComponent 并找到 my-app 选择器,定位到一个名字为 my-app 的元素,然后在这个标签之间的载入内容。

添加一些样式

styles.css 文件代码为:


styles.css 文件:

h1 { color: #369; font-family: Arial, Helvetica, sans-serif; font-size: 250%; } body { margin: 2em; }

打开终端,输入以下命令:

$ npm start

访问 http://localhost:3000/,浏览器显示结果为:

这样我们的第一个 Angular2 的应用就算创建完成了,本文所使用的源码可以通过以下方式下载,不包含 node_modules。

源代码下载

点我分享笔记


取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

点我查看本站打赏源码!

忘记密码?

如何获取邀请码?

关闭

Angular 2 TypeScript 环境配置

本章节使用的是 TypeScript 来创建 Angular 的应用,这也是官方推荐使用的,本教程的实例也将采用 TypeScript 来编写。

TypeScript 是一种由微软开发的自由和开源的编程语言,它是JavaScript的一个超集,扩展了JavaScript的语法。

如果你不了解TypeScript,可以查阅以下资料:

这开始前,你需要确保你已经安装了 npm,如果你还没安装npm或者不了解 npm 可以查看我们的教程:NPM 使用介绍

由于 npm 官网镜像国内访问太慢,这里我使用了淘宝的npm镜像,安装方法如下:

$ npm install -g cnpm --registry=https://registry.npm.taobao.org

执行后我们就可以使用 cnpm 命令来安装模块:

$ cnpm install

第一步:创建与配置项目

创建目录

$ mkdir angular-quickstart
$ cd angular-quickstart

创建配置文件

Angular 项目需要以下几个配置文件:

  • package.json 标记本项目所需的 npm 依赖包。
  • tsconfig.json 定义了 TypeScript 编译器如何从项目源文件生成 JavaScript 代码。
  • typings.json为那些 TypeScript 编译器无法识别的库提供了额外的定义文件。
  • systemjs.config.js 为模块加载器提供了该到哪里查找应用模块的信息,并注册了所有必备的依赖包。 它还包括文档中后面的例子需要用到的包。

在 angular-quickstart 中创建以下几个文件,代码如下所示:

package.json 文件:

{ "name": "angular-quickstart", "version": "1.0.0", "scripts": { "start": "tsc && concurrently \"npm run tsc:w\" \"npm run lite\" ", "lite": "lite-server", "postinstall": "typings install", "tsc": "tsc", "tsc:w": "tsc -w", "typings": "typings" }, "license": "ISC", "dependencies": { "@angular/common": "2.0.0", "@angular/compiler": "2.0.0", "@angular/core": "2.0.0", "@angular/forms": "2.0.0", "@angular/http": "2.0.0", "@angular/platform-browser": "2.0.0", "@angular/platform-browser-dynamic": "2.0.0", "@angular/router": "3.0.0", "@angular/upgrade": "2.0.0", "core-js": "^2.4.1", "reflect-metadata": "^0.1.3", "rxjs": "5.0.0-beta.12", "systemjs": "0.19.27", "zone.js": "^0.6.23", "angular2-in-memory-web-api": "0.0.20", "bootstrap": "^3.3.6" }, "devDependencies": { "concurrently": "^2.2.0", "lite-server": "^2.2.2", "typescript": "^2.3.4", "typings":"^1.3.2" } }

tsconfig.json 文件:

{ "compilerOptions": { "target": "es5", "module": "commonjs", "moduleResolution": "node", "sourceMap": true, "emitDecoratorMetadata": true, "experimentalDecorators": true, "removeComments": false, "noImplicitAny": false } }

typings.json 文件:

{ "globalDependencies": { "core-js": "registry:dt/core-js#0.0.0+20160725163759", "jasmine": "registry:dt/jasmine#2.2.0+20160621224255", "node": "registry:dt/node#6.0.0+20160909174046" } }

systemjs.config.js 文件:

/** * System configuration for Angular samples * Adjust as necessary for your application needs. */ (function (global) { System.config({ paths: { // paths serve as alias 'npm:': 'node_modules/' }, // map tells the System loader where to look for things map: { // our app is within the app folder app: 'app', // angular bundles '@angular/core': 'npm:@angular/core/bundles/core.umd.js', '@angular/common': 'npm:@angular/common/bundles/common.umd.js', '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js', '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js', '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js', '@angular/http': 'npm:@angular/http/bundles/http.umd.js', '@angular/router': 'npm:@angular/router/bundles/router.umd.js', '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js', // other libraries 'rxjs': 'npm:rxjs', 'angular2-in-memory-web-api': 'npm:angular2-in-memory-web-api', }, // packages tells the System loader how to load when no filename and/or no extension packages: { app: { main: './main.js', defaultExtension: 'js' }, rxjs: { defaultExtension: 'js' }, 'angular2-in-memory-web-api': { main: './index.js', defaultExtension: 'js' } } }); })(this);

接下来我们使用 cnpm 命令来安装依赖包:

$ cnpm install

执行成功后,angular-quickstart 目录下就会生成一个 node_modules 目录,这里包含了我们这个实例需要的模块,我们可以看下项目的目录结构:


第二步:创建应用

我们用 NgModules 把 Angular 应用组织成了一些功能相关的代码块。

Angular 本身是被拆成一些独立的 Angular 模块,这样我们在应用中只需要导入需要的 Angular 部分。

每个 Angular 应用至少需要一个root module(根模块) ,实例中为 AppModule 。

接下来我们在 angular-quickstart 目录下创建 app 目录:

$ mkdir app
$ cd app

然后在 app 目录下创建 app.module.ts 文件,代码如下所示:


app.module.ts 文件:

import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; @NgModule({ imports: [ BrowserModule ] }) export class AppModule { }

由于 QuickStart 是一个运行在浏览器中的 Web 应用,所以根模块需要从 @angular/platform-browser 中导入 BrowserModule 并添加到 imports 数组中。

创建组件并添加到应用中

每个 Angular 应用都至少有一个根组件, 实例中为 AppComponent,app.component.ts 文件代码如下:


app.component.ts 文件:

import { Component } from '@angular/core'; @Component({ selector: 'my-app', template: '<h1>我的第一个 Angular 应用</h1>' }) export class AppComponent { }

代码解析:

  • 以上代码从 angular2/core 引入了 Component 包。

  • @Component 是 Angular 2 的装饰器 ,它会把一份元数据关联到 AppComponent 组件类上。

  • my-app 是一个 CSS 选择器,可用在 HTML 标签中,作为一个组件使用。

  • @view 包含了一个 template ,告诉 Angular 如何渲染该组件的视图。

  • export 指定了组件可以在文件外使用。

接下来我们重新打开 app.module.ts 文件,导入新的 AppComponent ,并把它添加到 NgModule 装饰器的 declarations 和 bootstrap 字段中:


app.module.ts 文件:

import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppComponent } from './app.component'; @NgModule({ imports: [ BrowserModule ], declarations: [ AppComponent ], bootstrap: [ AppComponent ] }) export class AppModule { }

第四部:启动应用

接下来我们需要告诉 Angular 如何启动应用。

在 angular-quickstart/app 目录下创建 main.ts 文件,代码如下所示:


main.ts 文件:

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { AppModule } from './app.module'; const platform = platformBrowserDynamic(); platform.bootstrapModule(AppModule);

以上代码初始化了平台,让你的代码可以运行,然后在该平台上启动你的 AppModule。


定义该应用的宿主页面

在 angular-quickstart 目录下创建 index.html 文件,代码如下所示:


index.html 文件:

<html> <head> <title>Angular 2 实例 - 菜鸟教程(runoob.com)</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="styles.css"> <!-- 1. 载入库 --> <!-- IE 需要 polyfill --> <script src="node_modules/core-js/client/shim.min.js"></script> <script src="node_modules/zone.js/dist/zone.js"></script> <script src="node_modules/reflect-metadata/Reflect.js"></script> <script src="node_modules/systemjs/dist/system.src.js"></script> <!-- 2. 配置 SystemJS --> <script src="systemjs.config.js"></script> <script> System.import('app').catch(function(err){ console.error(err); }); </script> </head> <!-- 3. 显示应用 --> <body> <my-app>Loading...</my-app> </body> </html>

这里值得注意的地方有:

  • JavaScript 库: core-js 是为老式浏览器提供的填充库, zone.jsreflect-metadata 库是 Angular 需要的,而 SystemJS 库是用来做模块加载的。

  • SystemJS 的配置文件和脚本,可以导入并运行了我们刚刚在 main 文件中写的 app 模块。

  • <my-app> 标签是应用载入的地方

  • 添加一些样式

    我们可以在 angular-quickstart 目录的 styles.css 文件中设置我们需要的样式:


    styles.css 文件:

    /* Master Styles */ h1 { color: #369; font-family: Arial, Helvetica, sans-serif; font-size: 250%; } h2, h3 { color: #444; font-family: Arial, Helvetica, sans-serif; font-weight: lighter; } body { margin: 2em; }

    第六步:编译并运行应用程序

    打开终端窗口,输入以下命令:

    npm start
    

    访问 http://localhost:3000/,浏览器显示结果为:

    这样我们的第一个 Angular2 的应用就算创建完成了,最终的目录结构为:

    本文所使用的源码可以通过以下方式下载,不包含 node_modules 和 typings 目录。

    源代码下载

点我分享笔记


取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

点我查看本站打赏源码!

忘记密码?

如何获取邀请码?

关闭

Angular 2 架构

Angular 2 应用程序应用主要由以下 8 个部分组成:

  • 1、模块 (Modules)
  • 2、组件 (Components)
  • 3、模板 (Templates)
  • 4、元数据 (Metadata)
  • 5、数据绑定 (Data Binding)
  • 6、指令 (Directives)
  • 7、服务 (Services)
  • 8、依赖注入 (Dependency Injection)

下图展示了每个部分是如何相互工作的:

图中的模板 (Templates)是由 Angular 扩展的 HTML 语法组成,组件 (Components)类用来管理这些模板,应用逻辑部分通过服务 (Services)来完成,然后在模块中打包服务与组件,最后通过引导根模块来启动应用。

接下来我们会对以上 8 个部分分开解析:


模块

模块由一块代码组成,可用于执行一个简单的任务。

Angular 应用是由模块化的,它有自己的模块系统:NgModules。

每个 Angular 应该至少要有一个模块(根模块),一般可以命名为:AppModule。

Angular 模块是一个带有 @NgModule 装饰器的类,它接收一个用来描述模块属性的元数据对象。

几个重要的属性如下:

  • declarations (声明) - 视图类属于这个模块。 Angular 有三种类型的视图类: 组件 、 指令 和 管道 。

  • exports - 声明( declaration )的子集,可用于其它模块中的组件模板 。

  • imports - 本模块组件模板中需要由其它导出类的模块。

  • providers - 服务的创建者。本模块把它们加入全局的服务表中,让它们在应用中的任何部分都可被访问到。

  • bootstrap - 应用的主视图,称为根组件,它是所有其它应用视图的宿主。只有根模块需要设置 bootstrap 属性中。

一个最简单的根模块:

app/app.module.ts 文件:

import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; @NgModule({ imports: [ BrowserModule ], providers: [ Logger ], declarations: [ AppComponent ], exports: [ AppComponent ], bootstrap: [ AppComponent ] }) export class AppModule { }

接下来我们通过引导根模块来启动应用,开发过程通常在 main.ts 文件中来引导 AppModule ,代码如下:

app/main.ts 文件:

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { AppModule } from './app.module'; platformBrowserDynamic().bootstrapModule(AppModule);

组件(Components)

组件是一个模板的控制类用于处理应用和逻辑页面的视图部分。

组件是构成 Angular 应用的基础和核心,可用于整个应用程序中。

组件知道如何渲染自己及配置依赖注入。

组件通过一些由属性和方法组成的 API 与视图交互。

创建 Angular 组件的方法有三步:

  • 从 @angular/core 中引入 Component 修饰器
  • 建立一个普通的类,并用 @Component 修饰它
  • 在 @Component 中,设置 selector 自定义标签,以及 template 模板

模板(Templates)

Angular模板的默认语言就是HTML。

我们可以通过使用模板来定义组件的视图来告诉 Angular 如何显示组件。以下是一个简单是实例:

<div>
网站地址 : {{site}}
</div>

在Angular中,默认使用的是双大括号作为插值语法,大括号中间的值通常是一个组件属性的变量名。


元数据(Metadata)

元数据告诉 Angular 如何处理一个类。

考虑以下情况我们有一个组件叫作 Component ,它是一个类,直到我们告诉 Angular 这是一个组件为止。

你可以把元数据附加到这个类上来告诉 Angular Component 是一个组件。

在 TypeScript 中,我们用 装饰器 (decorator) 来附加元数据。

实例

@Component({
   selector : 'mylist',
   template : '<h2>菜鸟教程</h2>'
   directives : [ComponentDetails]
})
export class ListComponent{...}

@Component 装饰器能接受一个配置对象,并把紧随其后的类标记成了组件类。

Angular 会基于这些信息创建和展示组件及其视图。

@Component 中的配置项说明:

  • selector - 一个 css 选择器,它告诉 Angular 在 父级 HTML 中寻找一个 <mylist> 标签,然后创建该组件,并插入此标签中。

  • templateUrl - 组件 HTML 模板的地址。

  • directives - 一个数组,包含 此 模板需要依赖的组件或指令。

  • providers - 一个数组,包含组件所依赖的服务所需要的依赖注入提供者。


数据绑定(Data binding)

数据绑定为应用程序提供了一种简单而一致的方法来显示数据以及数据交互,它是管理应用程序里面数值的一种机制。

通过这种机制,可以从HTML里面取值和赋值,使得数据的读写,数据的持久化操作变得更加简单快捷。

如图所示,数据绑定的语法有四种形式。每种形式都有一个方向——从 DOM 来、到 DOM 去、双向,就像图中的箭头所示意的。

  • 插值 : 在 HTML 标签中显示组件值。

    <h3>
    {{title}}
    <img src="{{ImageUrl}}">
    </h3>
    
  • 属性绑定: 把元素的属性设置为组件中属性的值。

    <img [src]="userImageUrl">
    
  • 事件绑定: 在组件方法名被点击时触发。

    <button (click)="onSave()">保存</button>
    
  • 双向绑: 使用Angular里的NgModel指令可以更便捷的进行双向绑定。

    <input [value]="currentUser.firstName"
           (input)="currentUser.firstName=$event.target.value" >
    

指令(Directives)

Angular模板是动态的 。当 Angular 渲染它们时,它会根据指令对 DOM 进行修改。

指令是一个带有"指令元数据"的类。在 TypeScript 中,要通过 @Directive 装饰器把元数据附加到类上。

在Angular中包含以下三种类型的指令:

  • 属性指令:以元素的属性形式来使用的指令。
  • 结构指令:用来改变DOM树的结构
  • 组件:作为指令的一个重要子类,组件本质上可以看作是一个带有模板的指令。
<li *ngFor="let site of sites"></li>
<site-detail *ngIf="selectedSite"></site-detail>

*ngFor 告诉 Angular 为 sites 列表中的每个项生成一个 <li> 标签。

*ngIf 表示只有在选择的项存在时,才会包含 SiteDetail 组件。


服务(Services)

Angular2中的服务是封装了某一特定功能,并且可以通过注入的方式供他人使用的独立模块。

服务分为很多种,包括:值、函数,以及应用所需的特性。

例如,多个组件中出现了重复代码时,把重复代码提取到服务中实现代码复用。

以下是几种常见的服务:

  • 日志服务
  • 数据服务
  • 消息总线
  • 税款计算器
  • 应用程序配置

以下实例是一个日志服务,用于把日志记录到浏览器的控制台:

export class Logger {
  log(msg: any)   { console.log(msg); }
  error(msg: any) { console.error(msg); }
  warn(msg: any)  { console.warn(msg); }
}

依赖注入

控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫"依赖查找"(Dependency Lookup)。

通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。

在传统的开发模式中,调用者负责管理所有对象的依赖,循环依赖一直是梦魇,而在依赖注入模式中,这个管理权交给了注入器(Injector),它在软件运行时负责依赖对象的替换,而不是在编译时。这种控制反转,运行注入的特点即是依赖注入的精华所在。

Angular 能通过查看构造函数的参数类型,来得知组件需要哪些服务。 例如, SiteListComponent 组件的构造函数需要一个 SiteService:

constructor(private service: SiteService) { }

当 Angular 创建组件时,会首先为组件所需的服务找一个注入器( Injector ) 。

注入器是一个维护服务实例的容器,存放着以前创建的实例。

如果容器中还没有所请求的服务实例,注入器就会创建一个服务实例,并且添加到容器中,然后把这个服务返回给 Angular 。

当所有的服务都被解析完并返回时, Angular 会以这些服务为参数去调用组件的构造函数。 这就是依赖注入 。

点我分享笔记


取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

点我查看本站打赏源码!

忘记密码?

如何获取邀请码?

关闭

Angular 2 数据显示

本章节我们将为大家介绍如何将数据显示到用户界面上,可以使用以下三种方式:

  • 通过插值表达式显示组件的属性
  • 通过 NgFor 显示数组型属性
  • 通过 NgIf 实现按条件显示

通过插值表达式显示组件的属性

要显示组件的属性,插值是最简单的方式,格式为:{{属性名}}

以下代码基于 Angular 2 TypeScript 环境配置 来创建,你可以在该章节上下载源码,并修改以下提到的几个文件。

app/app.component.ts 文件:

import { Component } from '@angular/core'; @Component({ selector: 'my-app', template: ` <h1>{{title}}</h1> <h2>我喜欢的网站: {{mySite}}</h2> ` }) export class AppComponent { title = '站点列表'; mySite = '菜鸟教程'; }

Angular 会自动从组件中提取 title 和 mySite 属性的值,并显示在浏览器中,显示信息如下:

注意:模板是包在反引号 (`) 中的一个多行字符串,而不是单引号 (')。


使用 ngFor 显示数组属性

我们也可以循环输出多个站点,修改以下文件:

app/app.component.ts 文件:

import { Component } from '@angular/core'; @Component({ selector: 'my-app', template: ` <h1>{{title}}</h1> <h2>我喜欢的网站: {{mySite}}</h2> <p>网站列表:</p> <ul> <li *ngFor="let site of sites"> {{ site }} </li> </ul> ` }) export class AppComponent { title = '站点列表'; sites = ['菜鸟教程', 'Google', 'Taobao', 'Facebook']; mySite = this.sites[0]; }

代码中我们在模板使用 Angular 的 ngFor 指令来显示 sites 列表中的每一个条目,不要忘记 *ngFor 中的前导星号 (*) 。。

修改后,浏览器显示如下所示:

实例中 ngFor 循环了一个数组, 事实上 ngFor 可以迭代任何可迭代的对象。

接下来我们在 app 目录下创建 site.ts 的文件,代码如下:

app/site.ts 文件:

export class Site { constructor( public id: number, public name: string) { } }

以上代码中定义了一个带有构造函数和两个属性: id 和 name 的类。

接着我们循环输出 Site 类的 name 属性:

app/app.component.ts 文件:

import { Component } from '@angular/core'; import { Site } from './site'; @Component({ selector: 'my-app', template: ` <h1>{{title}}</h1> <h2>我喜欢的网站: {{mySite.name}}</h2> <p>网站列表:</p> <ul> <li *ngFor="let site of sites"> {{ site.name }} </li> </ul> ` }) export class AppComponent { title = '站点列表'; sites = [ new Site(1, '菜鸟教程'), new Site(2, 'Google'), new Site(3, 'Taobao'), new Site(4, 'Facebook') ]; mySite = this.sites[0]; }

修改后,浏览器显示如下所示:


通过 NgIf 进行条件显示

我们可以使用 NgIf 来设置输出指定条件的数据。

以下实例中我们判断如果网站数 3 个以上,输出提示信息:修改以下 app.component.ts 文件,代码如下:

app/app.component.ts 文件:

import { Component } from '@angular/core'; import { Site } from './site'; @Component({ selector: 'my-app', template: ` <h1>{{title}}</h1> <h2>我喜欢的网站: {{mySite.name}}</h2> <p>网站列表:</p> <ul> <li *ngFor="let site of sites"> {{ site.name }} </li> </ul> <p *ngIf="sites.length > 3">你有很多个喜欢的网站!</p> ` }) export class AppComponent { title = '站点列表'; sites = [ new Site(1, '菜鸟教程'), new Site(2, 'Google'), new Site(3, 'Taobao'), new Site(4, 'Facebook') ]; mySite = this.sites[0]; }

修改后,浏览器显示如下所示,底部多了个提示信息:

点我分享笔记


取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

点我查看本站打赏源码!

忘记密码?

如何获取邀请码?

关闭

Angular 2 用户输入

用户点击链接、按下按钮或者输入文字时,这些用户的交互行为都会触发 DOM 事件。

本章中,我们将学习如何使用 Angular 事件绑定语法来绑定这些事件。

以下Gif图演示了该实例的操作:

源代码可以在文章末尾下载。


绑定到用户输入事件

我们可以使用 Angular 事件绑定机制来响应任何 DOM 事件 。

以下实例将绑定了点击事件:

<button (click)="onClickMe()">点我!</button>

等号左边的 (click) 表示把该按钮的点击事件作为绑定目标 。 等号右边,引号中的文本是一个 模板语句

完整代码如下:

app/click-me.component.ts 文件:

import { Component } from '@angular/core'; @Component({ selector: 'click-me', template: ` <button (click)="onClickMe()">点我!</button> {{clickMessage}}` }) export class ClickMeComponent { clickMessage = ''; onClickMe() { this.clickMessage = '菜鸟教程!'; } }

通过 $event 对象取得用户输入

我们可以绑定到所有类型的事件。

让我们试试绑定到一个输入框的 keyup 事件,并且把用户输入的东西回显到屏幕上。

app/keyup.component.ts (v1) 文件:

@Component({ selector: 'key-up1', template: ` <input (keyup)="onKey($event)"> <p>{{values}}</p> ` }) export class KeyUpComponent_v1 { values = ''; /* // 非强类型 onKey(event:any) { this.values += event.target.value + ' | '; } */ // 强类型 onKey(event: KeyboardEvent) { this.values += (<HTMLInputElement>event.target).value + ' | '; } }

以上代码中我们监听了一个事件并捕获用户输入,Angular 把事件对象存入 $event 变量中。

组件的 onKey() 方法是用来从事件对象中提取出用户输入的,再将输入的值累加到 values 的属性。


从一个模板引用变量中获得用户输入

你可以通过使用局部模板变量来显示用户数据,模板引用变量通过在标识符前加上井号 (#) 来实现。

下面的实例演示如何使用局部模板变量:

app/loop-back.component.ts 文件:

@Component({ selector: 'loop-back', template: ` <input #box (keyup)="0"> <p>{{box.value}}</p> ` }) export class LoopbackComponent { }

我们在 <input> 元素上定义了一个名叫 box 的模板引用变量。 box 变量引用的就是 <input> 元素本身,这意味着我们可以获得 input 元素的 value 值,并通过插值表达式把它显示在 <p> 标签中。

我们可以使用模板引用变量来修改以上 keyup 的实例:

app/keyup.components.ts (v2) 文件:

@Component({ selector: 'key-up2', template: ` <input #box (keyup)="onKey(box.value)"> <p>{{values}}</p> ` }) export class KeyUpComponent_v2 { values = ''; onKey(value: string) { this.values += value + ' | '; } }

按键事件过滤 ( 通过 key.enter)

我们可以只在用户按下回车 (enter) 键的时候才获取输入框的值。

(keyup) 事件处理语句会听到每一次按键,我们可以过滤按键,比如每一个 $event.keyCode,只有在按下回车键才更新 values 属性。

Angular 可以为我们过滤键盘事件,通过绑定到 Angular 的 keyup.enter 伪事件监听回车键的事件。

app/keyup.components.ts (v3):

@Component({ selector: 'key-up3', template: ` <input #box (keyup.enter)="values=box.value"> <p>{{values}}</p> ` }) export class KeyUpComponent_v3 { values = ''; }

blur( 失去焦点 ) 事件

接下来我们可以使用blur( 失去焦点 ) 事件,它可以再元素失去焦点后更新 values 属性。

以下实例同时监听输入回车键与输入框失去焦点的事件。

app/keyup.components.ts (v4):

@Component({ selector: 'key-up4', template: ` <input #box (keyup.enter)="values=box.value" (blur)="values=box.value"> <p>{{values}}</p> ` }) export class KeyUpComponent_v4 { values = ''; }

本文所使用的源码可以通过以下方式下载,不包含 node_modules 和 typings 目录。

源代码下载

点我分享笔记


取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

点我查看本站打赏源码!

忘记密码?

如何获取邀请码?

关闭

Angular 2 表单

本章节我们将为大家介绍如何使用组件和模板构建一个 Angular 表单。

利用 Angular 模板,我们可以创建各种类型表单,例如:登录表单,联系人表单,商品详情表单等,而且我们也为这些表单的字段添加数据校验。

接下来我们一步步来实现表单的功能。


创建项目

导入初始化项目。

完整的项目创建可以参考:Angular 2 TypeScript 环境配置

或者直接下载源代码:点我下载

解压后,修改目录名为angular-forms,修改 angular-forms/package.json 文件中的 "name": "angular-quickstart""name": "angular-forms"

完成后,我们执行 cnpm install 来载入依赖包。

创建 Site 模型

以下创建了一个简单的模型类 Site,包含了三个必需字段:id,name,url,一个可选字段:alexa。

在 angular-forms/app 目录下创建 site.ts 文件,代码如下:

app/site.ts 文件:

export class Site { constructor( public id: number, public name: string, public url: string, public alexa?: number ) { } }

以下代码中,标为 public 的为公有字段,alexa 后添加一个问号(?)表示可选字段。

创建一个表单组件

每个 Angular 表单分为两部分:一个基于 HTML 的模板,和一个基于代码的组件,它用来处理数据和用户交互。

在 angular-forms/app 目录下创建 site-form.component.ts 文件,代码如下:

app/site-form.component.ts 文件:

import { Component } from '@angular/core'; import { Site } from './site'; @Component({ moduleId: module.id, selector: 'site-form', templateUrl: 'site-form.component.html' }) export class SiteFormComponent { urls = ['www.runoob.com', 'www.google.com', 'www.taobao.com', 'www.facebook.com']; model = new Site(1, '菜鸟教程', this.urls[0], 10000); submitted = false; onSubmit() { this.submitted = true; } // TODO: 完成后移除 get diagnostic() { return JSON.stringify(this.model); } }

实例中导入了 Component 装饰器和 Site 模型。

@Component 选择器 "site-form" 表示我们可以通过一个 <site-form> 标签,把此表单扔进父模板中。

templateUrl 属性指向一个独立的HTML模板文件,名叫 site-form.component.html。

diagnostic 属性用于返回这个模型的JSON形式。

定义应用的根模块

修改 app.module.ts 来定义应用的根模块,模块中指定了引用到的外部及声明属于本模块中的组件,比如 SiteFormComponent。

因为模板驱动的表单有它们自己的模块,所以我们得把 FormsModule 添加到本应用的 imports 数组中,这样我们才能使用表单。

app/app.module.ts 文件代码如下

app/app.module.ts 文件:

import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { FormsModule } from '@angular/forms'; import { AppComponent } from './app.component'; import { SiteFormComponent } from './site-form.component'; @NgModule({ imports: [ BrowserModule, FormsModule ], declarations: [ AppComponent, SiteFormComponent ], bootstrap: [ AppComponent ] }) export class AppModule { }

创建根组件

修改根组件文件 app.component.ts,将 SiteFormComponent 放在其中。

app/app.component.ts 文件:

import { Component } from '@angular/core'; @Component({ selector: 'my-app', template: '<site-form></site-form>' }) export class AppComponent { }

创建一个初始 HTML 表单模板

创建模板文件 site-form.component.html ,代码如下所示:

app/site-form.component.html 文件:

<div class="container"> <h1>网站表单</h1> <form> <div class="form-group"> <label for="name">网站名</label> <input type="text" class="form-control" id="name" required> </div> <div class="form-group"> <label for="alexa">alexa 排名</label> <input type="text" class="form-control" id="alexa"> </div> <button type="submit" class="btn btn-default">提交</button> </form> </div>

required 属性设置的该字段为必需字段,如果没有设置则是可选。

在 angular-forms 目录下输入以下命令:

cnpm install bootstrap --save

打开 index.html 文件,把以下样式链接添加到 <head> 中:

<link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.min.css">

执行 npm start 后,访问:http://localhost:3000/,输出效果如下:


使用 ngModel 进行双向数据绑定

接下来我们使用 ngModel 进行双向数据绑定,通过监听 DOM 事件,来实现更新组件的属性。

修改 app/site-form.component.html ,使用 ngModel 把我们的表单绑定到模型。代码如下所示:

app/site-form.component.html 文件:

<div class="container"> <h1>网站表单</h1> <form> {{diagnostic}} <div class="form-group"> <label for="name">网站名</label> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name"> </div> <div class="form-group"> <label for="alexa">alexa 排名</label> <input type="text" class="form-control" id="alexa" [(ngModel)]="model.alexa" name="alexa"> </div> <div class="form-group"> <label for="url">网站 URL </label> <select class="form-control" id="url" required [(ngModel)]="model.url" name="url"> <option *ngFor="let p of urls" [value]="p">{{p}}</option> </select> </div> <button type="submit" class="btn btn-default">提交</button> </form> </div>
  • 每一个 input 元素都有一个 id 属性,它被 label 元素的 for 属性用来把标签匹配到对应的 input 。

  • 每一个 input 元素都有一个 name 属性, Angular 的表单模块需要使用它为表单注册控制器。

运行以上实例输出结果如下:

{{diagnostic}} 只是用于测试时候输出数据使用。

我们还可以通过 ngModel 跟踪修改状态与有效性验证,它使用了三个 CSS 类来更新控件,以便反映当前状态。

状态 为 true 时的类 为 false 时的类
控件已经被访问过 ng-touched ng-untouched
控件值已经变化 ng-dirty ng-pristine
控件值是有效的 ng-valid ng-invalid

这样我们就可以添加自定义 CSS 来反应表单的状态。

在 angular-forms 目录下创建 forms.css 文件,代码如下:

forms.css 文件:

.ng-valid[required], .ng-valid.required { border-left: 5px solid #42A948; /* green */ } .ng-invalid:not(form) { border-left: 5px solid #a94442; /* red */ }

打开 index.html 文件,把以下样式链接添加到 <head> 中:

<link rel="stylesheet" href="forms.css">

修改 app/site-form.component.html ,代码如下所示:

app/site-form.component.html 文件:

<div class="container"> <h1>网站表单</h1> <form> {{diagnostic}} <div class="form-group"> <label for="name">网站名</label> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name" #name="ngModel" > <div [hidden]="name.valid || name.pristine" class="alert alert-danger"> 网站名是必需的 </div> </div> <div class="form-group"> <label for="alexa">alexa 排名</label> <input type="text" class="form-control" id="alexa" [(ngModel)]="model.alexa" name="alexa"> </div> <div class="form-group"> <label for="url">网站 URL </label> <select class="form-control" id="url" required [(ngModel)]="model.url" name="url"> <option *ngFor="let p of urls" [value]="p">{{p}}</option> </select> </div> <button type="submit" class="btn btn-default">提交</button> </form> </div>

模板中通过把 div 元素的 hidden 属性绑定到 name 控件的属性,我们就可以控制"name"字段错误信息的可见性了。

删除掉 name 字段的数据,显示结果如下所示:

添加一个网站

接下来我们创建一个用于添加网站的表单,在 app/site-form.component.html 添加一个按钮:

app/site-form.component.html 文件:

<button type="button" class="btn btn-default" (click)="newSite()">添加网站</button>

将以上按钮事件绑定到组件方法上:

app/site-form.component.ts 文件:

active = true; newSite() { this.model = new Site(5, '', ''); this.active = false; setTimeout(() => this.active = true, 0); }

我们给组件添加一个 active 标记,把它初始化为 true 。当我们添加一个新的网站时,它把 active 标记设置为 false , 然后通过一个快速的 setTimeout 函数迅速把它设置回 true 。

通过 ngSubmit 来提交表单

我们可以使用 Angular 的指令 NgSubmit 来提交表单, 并且通过事件绑定机制把它绑定到 SiteFormComponent.submit() 方法上。

<form *ngIf="active" (ngSubmit)="onSubmit()" #siteForm="ngForm">

我们定义了一个模板引用变量 #siteForm ,并且把它初始化为 "ngForm" 。

这个 siteForm 变量现在引用的是 NgForm 指令,它代表的是表单的整体。

site-form.component.ts 文件完整代码如下:

app/site-form.component.ts 文件:

import { Component } from '@angular/core'; import { Site } from './site'; @Component({ moduleId: module.id, selector: 'site-form', templateUrl: 'site-form.component.html' }) export class SiteFormComponent { urls = ['www.runoob.com', 'www.google.com', 'www.taobao.com', 'www.facebook.com']; model = new Site(1, '菜鸟教程', this.urls[0], 10000); submitted = false; onSubmit() { this.submitted = true; } // TODO: 完成后移除 get diagnostic() { return JSON.stringify(this.model); } active = true; newSite() { this.model = new Site(5, '', ''); this.active = false; setTimeout(() => this.active = true, 0); } }

app/site-form.component.html 完整代码如下:

app/site-form.component.html 文件:

<div class="container"> <div [hidden]="submitted"> <h1>网站表单</h1> <form *ngIf="active" (ngSubmit)="onSubmit()" #siteForm="ngForm"> {{diagnostic}} <div class="form-group"> <label for="name">网站名</label> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name" #name="ngModel" > <div [hidden]="name.valid || name.pristine" class="alert alert-danger"> 网站名是必需的 </div> </div> <div class="form-group"> <label for="alexa">alexa 排名</label> <input type="text" class="form-control" id="alexa" [(ngModel)]="model.alexa" name="alexa"> </div> <div class="form-group"> <label for="url">网站 URL </label> <select class="form-control" id="url" required [(ngModel)]="model.url" name="url"> <option *ngFor="let p of urls" [value]="p">{{p}}</option> </select> </div> <button type="submit" class="btn btn-default" [disabled]="!siteForm.form.valid">提交</button> <button type="button" class="btn btn-default" (click)="newSite()">新增网站</button> </form> </div> <div [hidden]="!submitted"> <h2>你提交的信息如下:</h2> <div class="row"> <div class="col-xs-3">网站名</div> <div class="col-xs-9 pull-left">{{ model.name }}</div> </div> <div class="row"> <div class="col-xs-3">网站 alexa 排名</div> <div class="col-xs-9 pull-left">{{ model.alexa }}</div> </div> <div class="row"> <div class="col-xs-3">网站 URL </div> <div class="col-xs-9 pull-left">{{ model.url }}</div> </div> <br> <button class="btn btn-default" (click)="submitted=false">编辑</button> </div> </div>

模板中我们把 hidden 属性绑定到 SiteFormComponent.submitted 属性上。

主表单从一开始就是可见的,因为 submitted 属性是 false ,当我们提交了这个表单则隐藏,submitted 属性是 true:

submitted = false; onSubmit() { this.submitted = true; }

最终的目录结构为:

本文所使用的源码可以通过以下方式下载,不包含 node_modules 和 typings 目录。

源代码下载

完整实例演示 GIf 如下:

点我分享笔记


取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

点我查看本站打赏源码!

忘记密码?

如何获取邀请码?

关闭

Angular 2 模板语法

前面几个章节我们已经接触了 Angular 的模板,本文我们将具体介绍 Angular 的语法使用。

模板扮演的是一个视图的角色,简单讲就是展示给用户看的部分。

  • HTML
  • 插值表达式
  • 模板表达式
  • 模板语句
  • 绑定语法
  • 属性绑定
  • HTML 属性、 class 和 style 绑定
  • 事件绑定
  • 使用 NgModel 进行双向数据绑定
  • 内置指令
  • * 与 <template>
  • 模板引用变量
  • 输入输出属性
  • 模板表达式操作符

HTML

HTML 是 Angular 模板的"语言",除了 <script> 元素是被禁用的外 ,其他 HTML 元素都是支持的,例如:

<h1>我的第一个 Angular 应用</h1>


插值表达式

插值表达式的语法格式为:{{ ... }}

插值表达式可以把计算的字符串插入HTML中,也可以作为属性值来使用。

<h3> {{title}} <img src="{{imageUrl}}" style="height:30px"> </h3>

模板表达式

{{ ... }} 里头其实就是一个模板表达式,Angular 会对其进行求值并转化为字符串输出。

以下实例是两个数相加:

<!-- "The sum of 1 + 1 is 2" --> <p>The sum of 1 + 1 is {{1 + 1}}</p>

我们可以使用 getVal() 来获取这个表达式的值:

<div class="example"> <div class="example_code"> [mycode3 type="html"] <!-- "4" --> <p>{{1 + 1 + getVal()}}</p>

模板表达式类似 JavaScript 的语言,很多 JavaScript 表达式也是合法的模板表达式,但不是全部。

以下 JavaScript 表达式是禁止的:

  • 赋值表达式(=+=-=...)
  • new操作符
  • 带有;或者'的连接表达式
  • 自增和自减操作(++--) 其他与Javascript语法不同的值得注意的包括:
  • 不支持位运算符(|&
  • 模板表达式的操作符,如|?.等,被赋予了新的含义

属性绑定

模板的属性绑定可以把视图元素的属性设置为模板表达式 。

最常用的属性绑定是把元素的属性设置为组件中属性的值。 下面这个例子中, image 元素的 src 属性会被绑定到组件的 imageUrl 属性上:

<img [src]="imageUrl">

当组件为 isUnchanged( 未改变 ) 时禁用一个按钮:

<button [disabled]="isUnchanged">按钮是禁用的</button>

设置指令的属性:

<div [ngClass]="classes">[ngClass]绑定到classes 属性</div>

设置一个自定义组件的属性(这是父子组件间通讯的重要途径):

<user-detail [user]="currentUser"></user-detail>

HTML 属性(Attribute)、 class 和 style 绑定

模板语法为那些不太适合使用属性绑定的场景提供了专门的单向数据绑定形式。

属性(Attribute)、绑定

当元素没有属性可绑的时候,使用HTML标签属性(Attribute)绑定。

考虑 ARIA, SVG 和 table 中的 colspan/rowspan 等属性(Attribute) 。它们是纯粹的属性 。 它们没有对应的属性可供绑定。

以下实例会报错:

<tr><td colspan="{{1 + 1}}">Three-Four</td></tr>

我们会得到这个错误:

Template parse errors:
Can't bind to 'colspan' since it isn't a known native property

模板解析错误:不能绑定到'colspan',因为它不是已知的原生属性

正如提示中所说, <td> 元素没有 colspan 属性。 但是插值表达式和属性绑定只能设置 属性 ,而不是 Attribute,所以需HTML标签 Attribute 绑定来创建和绑定类似的Attribute。

HTML标签特性绑定在语法上类似于属性绑定,但中括号中的部分不是一个元素的属性名,而是由一个attr.的前缀和HTML标签属性的名称组成,然后通过一个能求值为字符串的表达式来设置HTML标签属性的值。如:

<table border=1> <tr><td [attr.colspan]="1 + 1">One-Two</td></tr> <tr><td>Five</td><td>Six</td></tr> </table>

css类绑定

借助 CSS 类绑定 ,我们可以从元素的 class 属性上添加和移除 CSS 类名。

CSS 类绑定在语法上类似于属性绑定。但方括号中的部分不是一个元素的属性名,而是包括一个 class 前缀,紧跟着一个点 (.) ,再跟着 CSS 类的名字组成。 其中后两部分是可选的。例如: [class.class-name]

下面的例子展示了如何通过css类绑定类添加和移除"special"类:

<!-- 标准HTML样式类设置 --> <div class="bad curly special">Bad curly special</div> <!-- 通过绑定重设或覆盖样式类 --> <div class="bad curly special" [class]="badCurly">Bad curly</div> <!-- 通过一个属性值来添加或移除special样式类 --> <div [class.special]="isSpecial">这个样式比较特殊</div>

style样式绑定

通过样式绑定,可以设置内联样式。样式绑定语法上类似于属性绑定,但中括号里面的部分不是一个元素的属性名,样式绑定包括一个style.,紧跟着css样式的属性名,例如:[style.style-property]。

<button [style.color] = "isSpecial ? 'red': 'green'">红色</button> <button [style.background-color]="canSave ? 'cyan': 'grey'" >保存</button> <!-- 带有单位的样式绑定 --> <button [style.font-size.em]="isSpecial ? 3 : 1" ></button> <button [style.font-size.%]="!isSpecial ? 150 : 50" ></button>

样式属性可以是中线命名法(font-size),也可以是驼峰是命名法(fontSize)。


事件绑定

在事件绑定中,Angular通过监听用户动作,比如键盘事件、鼠标事件、触屏事件等来响应相对应的数据流向-从视图目标到数据源。

事件绑定的语法是由等号左侧小括号内的 目标事件 和右侧引号中的 模板声明 组成。

比如下面这个例子,是事件绑定监听按钮的点击事件。只要点击鼠标,都会调用组件的 onSave()方法。

<button (click)="onSave()">保存</button>

圆括号中的名称 ——比如 (click) ——标记出了目标事件。在下面这个例子中,目标是按钮的 click 事件。

<button (click)="onSave()">Save</button>

也可以使用on- 前缀的形式:

<button on-click="onSave()">On Save</button>

使用 NgModel 进行双向数据绑定

当开发数据输入表单时,期望的结果是既能将组件的数据显示到表单上,也能在用户修改时更新组件的数据。

以下是一个通过 [(NgModel)] 来实现双向绑定:

<input [(ngModel)]="currentUser.firstName">

[]实现了数据流从组件到模板,()实现了数据流从模板到组件,两者一结合[()]就实现了双向绑定。

使用前缀形式的语法:

<input bindon-ngModel="currentUser.firstName">

内置指令

Angular 的内置指令有 NgClass、NgStyle、NgIf、NgFor、NgSwitch等。

NgClass

通过绑定到 NgClass 动态添加或删除 CSS 类。

<div [style.font-size]="isSpecial ? 'x-large' : 'smaller'" > 这个div是大号的。 </div>

NgStyle

NgStyle 通过把它绑定到一个key:value控制对象的形式,可以让我们同时设置很多内联样式。

setStyles() { let styles = { // CSS属性名 'font-style': this.canSave ? 'italic' : 'normal', // italic 'font-weight': !this.isUnchanged ? 'bold' : 'normal', // normal 'font-size': this.isSpecial ? '24px' : '8px', // 24px }; return styles; }

通过添加一个NgStyle属性绑定,让它调用setStyles,并据此来设置元素的样式:

<div [ngStyle]="setStyles()"> 这个div的样式是italic, normal weight, 和extra large (24px)。 </div>

NgIf

通过把NgIf指令绑定到一个真值表达式,可以把一个元素及其子元素添加到DOM树上。

<div *ngIf="currentUser">Hello,{{currentUser.firstName}}</div>

相反,绑定到一个假值表达式将从DOM树中移除该元素及其子元素。如:

<!-- 因为isActive的值为false,所以User Detail不在DOM树中--> <user-detail *ngIf="isActive"></user-detail>

NgSwitch

当需要从一组可能的元素树中根据条件显示其中一个时,就需要NgSwitch了。Angular将只把选中的元素添加进DOM中。如:

<span [ngSwitch]="userName"> <span *ngSwitchCase="'张三'">张三</span> <span *ngSwitchCase="'李四'">李四</span> <span *ngSwitchCase="'王五'">王五</span> <span *ngSwitchCase="'赵六'">赵六</span> <span *ngSwitchDefault>龙大</span> </span>

把作为父指令的NgSwitch绑定到一个能返回开关值的表达式,例子中这个值是字符串,但它可以是任何类型的值。父指令NgSwitch控制一组<span>子元素。每个<span>或者挂在一个匹配值的表达式上,或者被标记为默认情况。任何时候,这些span中最多只有一个会出现在DOM中。如果这个span的匹配值和开关值相等,Angular2就把这个<span>添加DOM中。如果没有任何span匹配上,Angular2就会把默认的span添加到DOM中。Angular2会移除并销毁所有其他的span。

三个相互合作的指令:

  • ngSwitch:绑定到一个返回开关值的表达式
  • ngSwitchCase:绑定到一个返回匹配值的表达式
  • ngSwitchDefault:一个用于标记默认元素的属性 注意:不要再ngSwitch前使用*,而应该用属性绑定,但ngSwitchCase和ngSwitchDefault前面要放*

NgFor

当需要展示一个由多个条目组成的列表时就需要这个指令了。如下面这个例子,就是在一个HTML块上应用NgFor。

<div *ngFor="let user of users">{{user.fullName}}</div>

NgFor也可以应用在一个组件元素上,如:

<user-detail *ngFor="let user of users" [user]="user"></user-detail>

ngFor指令支持一个可选的index索引,在迭代过程中会从0增长到数组中的长度。

可以通过模板输入变量来捕获这个index,并应用在模板中。下面的例子就把index捕获到了一个名为i的变量中。

<div *ngFor="let user of users; let i=index">{{i + 1}} - {{user.fullName}}</div>

NgForTrackBy

ngFor 指令有时候会性能较差,特别是在大型列表中。 对一个条目的一点小更改、移除或添加,都会导致级联的 DOM 操作。

比如,当通过重新从服务器来刷新通讯录,刷新后的列表可能包含很多(如果不是全部的话)以前显示过的联系人。但在Angular看来,它不知道哪些是以前就存在过的,只能清理旧列表、舍弃那些DOM元素,并用新的DOM元素来重建一个新列表。

解决这个问题,可以通过追踪函数来避免这种折腾。追踪函数会告诉Angular:我们知道两个具有相同user.id的对象是同一个联系人。如:

trackByUsers(index: number, user: User){return user.id}

然后,把NgForTrackBy指令设置为那个追踪函数:

<div *ngFor="let user of users; trackBy:trackByUsers">({{user.id}}) {{user.fullName}}</div>

追踪函数不会排除所有DOM更改。如果用来判断是否为同一个联系人的属性变化了,就会更新DOM元素,反之就会留下这个DOM元素。列表界面就会变得比较更加平滑,具有更好的响应效果。


模板引用变量

模板引用变量是模板中对 DOM 元素或指令的引用。

它能在原生 DOM 元素中使用,也能用于 Angular 组件——实际上,它可以和任何自定义 Web 组件协同工作。

我们可以在同一元素、兄弟元素或任何子元素中引用模板引用变量。

这里是关于创建和使用模板引用变量的两个例子:

<!-- phone 引用了 input 元素,并将 `value` 传递给事件句柄 --> <input #phone placeholder="phone number"> <button (click)="callPhone(phone.value)">Call</button> <!-- fax 引用了 input 元素,并将 `value` 传递给事件句柄 --> <input ref-fax placeholder="fax number"> <button (click)="callFax(fax.value)">Fax</button>

"phone" 的 (#) 前缀意味着我们将要定义一个 phone 变量。

点我分享笔记


取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

点我查看本站打赏源码!

忘记密码?

如何获取邀请码?

关闭