Angular 4 基础教程

本系列教程的主要内容来源于 egghead.io get-started-with-angular 视频教程,但针对视频中的介绍的知识点做了适当地补充,建议有兴趣的同学直接查看该视频教程。
另外建了个群有兴趣的朋友可以加一下 QQ 群:Angular 修仙之路 - 153742079 (群名称规则:城市 + 昵称)

目录

  • 第一节 - 基于 Angular CLI 新建项目
  • 第二节 - 创建简单的组件
  • ​第三节 - 事件和模板引用
  • 第四节 - 事件进阶
  • 第五节 - 注入服务
  • 第六节 - 使用 ngFor 指令
  • 第七节 - 使用 Input 装饰器
  • 第八节 - 使用双向绑定
  • 第九节 - 使用 Output 装饰器
  • 第十节 - 组件样式
查看新版教程,请访问 Angular 6.x 基础教程

第一节 - 基于 Angular CLI 新建项目

安装 Angular CLI (可选)

  • 安装 Angular CLI (可选)
$ npm install -g @angular/cli
  • 检测 Angular CLI 是否安装成功
$ ng --version

使用 Angular CLI

  • 新建项目
$ ng new angular4-fundamentals
  • 启动本地服务器
$ ng serve

若想进一步了解 Angular CLI 的详细信息,请参考 Angular CLI 终极指南。

第二节 - 创建简单的组件

新建组件

$ ng generate component simple-form --inline-template --inline-style
# Or
$ ng g c simple-form -it -is # 表示新建组件,该组件使用内联模板和内联样式

在命令行窗口运行以上命令后,将输出以下内容:

installing component
  create src/app/simple-form/simple-form.component.spec.ts
  create src/app/simple-form/simple-form.component.ts
  update src/app/app.module.ts

即执行上述操作后,创建了两个文件:

  • simple-form.component.spec.ts - 用于单元测试
  • simple-form.component.ts - 新建的组件

除此之外,update src/app/app.module.ts 表示执行上述操作后,Angular CLI 会自动帮我们更新 app.module.ts 文件。所更新的内容是把我们新建的组件添加到 NgModuledeclarations 数组中,具体如下:

@NgModule({
  declarations: [
    AppComponent,
    SimpleFormComponent
  ],
  ...
})
export class AppModule { }

使用组件

AppComponent

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `
    

{{title}}

` }) export class AppComponent { title = 'Hello, Angular'; }

SimpleFormComponent

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-simple-form',
  template: `
    

simple-form Works!

`, styles: [] }) export class SimpleFormComponent implements OnInit { constructor() { } ngOnInit() { } }

从生成的 SimpleFormComponent 组件中,我们发现组件的 selectorapp-simple-form,而我们是使用以下命令创建该组件:

$ ng g c simple-form -it -is

即 Angular CLI 在创建组件时,自动帮我们添加了前缀。那为什么前缀是 app 呢?答案是在项目根目录下的 .angular-cli.json 文件中,已经默认帮我们配置了默认的前缀,具体如下:

{
  ...
  "apps": [
    {
      "root": "src",
      "outDir": "dist",
      ...
      "prefix": "app",
       ...
    }
  ],
}

当然你可以根据实际需求,自行更改默认的前缀配置。

第三节 - 事件和模板引用

在 Angular 中,我们可以使用 (eventName) 语法,进行事件绑定。此外,可以使用 #variableName 的语法,定义模板引用。具体示例如下:

SimpleFormComponent

import {Component, OnInit} from '@angular/core';

@Component({
  selector: 'app-simple-form',
  template: `
    
`, styles: [] }) export class SimpleFormComponent implements OnInit { onClick(value) { console.log(value); } ngOnInit() {} }

需要注意的是,若我们改变绑定的表达式为 (click)="onClick(myInput)" ,当我们点击按钮时,控制台输出的结果是:

通过该输出结果,我们可以知道 #variableName 语法,我们获取的对象是对应 DOM 元素的引用。

第四节 - 事件进阶

获取鼠标事件

在第三节的示例中,假如我们需要获取鼠标事件,那应该怎么办呢?这时,我们可以引入 $event 变量,具体如下:

import {Component, OnInit} from '@angular/core';

@Component({
  selector: 'app-simple-form',
  template: `
    
`, styles: [] }) export class SimpleFormComponent implements OnInit { onClick(event, value) { console.log(event); console.log(value); } ngOnInit() {} }

成功运行以上代码,当我们点击按钮时,控制台将输出:

MouseEvent {isTrusted: true, screenX: 180, screenY: 207, clientX: 165,
  clientY: 75…}

需要注意的是,参数名一定要使用 $event ,否则无法获取正确的鼠标事件。此外,onClick($event, myInput.value) 表达式中,$event 的顺序是任意的,如:

当 Angular 在调用我们的事件处理函数时,会自动帮我们处理调用的参数。$event 自动映射为触发的事件,与我们 ProviderToken 的作用类似。除了监听鼠标事件外,我们还可以监听键盘事件。

获取键盘事件

import {Component, OnInit} from '@angular/core';

@Component({
  selector: 'app-simple-form',
  template: `
    
`, styles: [] }) export class SimpleFormComponent implements OnInit { // ... onEnter(event, value) { console.log(event); console.log(value); } }

以上代码中, (keydown.enter)="onEnter($event, myInput.value)" 表达式表示我们监听键盘 enter 键的按下事件,当我们按下键盘的 enter 键时,将会调用组件类中定义的 onEnter() 方法。我们同样也可以通过 $event 来获取 KeyboardEvent 对象。

第五节 - 注入服务

新建服务

$ ng g s mail

在命令行窗口运行以上命令后,将输出以下内容:

installing service
  create src/app/mail.service.spec.ts
  create src/app/mail.service.ts
  WARNING Service is generated but not provided, it must be provided to be used

即执行上述操作后,创建了两个文件:

  • mail.service.spec.ts - 用于单元测试
  • mail.service.ts - 新建的服务

除此之外,WARNING Service is generated but not provided,... 表示执行上述操作后,Angular CLI 只会帮我们创建 MailService 服务,不会自动帮我们配置该服务。

配置服务

import {MailService} from "./mail.service";

@NgModule({
  ...
  providers: [MailService],
  bootstrap: [AppComponent]
})
export class AppModule { }

更新服务

import { Injectable } from '@angular/core';

@Injectable()
export class MailService {
  message: string  ='该消息来自MailService';
  constructor() { }
}

使用服务

import { Component } from '@angular/core';
import {MailService} from "./mail.service";

@Component({
  selector: 'app-root',
  template: `
    

{{title}}

{{mailService.message}}
` }) export class AppComponent { title = 'Hello, Angular'; constructor(private mailService: MailService) {} }

除了使用 constructor(private mailService: MailService) 方式注入服务外,我们也可以使用 Inject 装饰器来注入 MailService 服务:

import {Component, Inject} from '@angular/core';

@Component({...})
export class AppComponent {
  title = 'Hello, Angular';
  
  constructor(@Inject(MailService) private mailService) {}
}

不过对于 Type 类型(函数类型) 的对象,我们一般使用 constructor(private mailService: MailService) 方式进行注入。而 Inject 装饰器一般用来注入非 Type 类型的对象。

使用Inject装饰器

AppModule

@NgModule({
  ...
  providers: [
    MailService,
    {provide: 'apiUrl', useValue: 'https://jsonplaceholder.typicode.com/'}
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

AppComponent

@Component({
  selector: 'app-root',
  template: `
    

{{title}}

{{mailService.message}}

API_URL: {{apiUrl}}

` }) export class AppComponent { title = 'Hello, Angular'; constructor( @Inject(MailService) private mailService, @Inject('apiUrl') private apiUrl ) {} }

第六节 - 使用 ngFor 指令

在 Angular 中我们可以使用 ngFor 指令来显示数组中每一项的信息。

使用 ngFor 指令

更新 MailService 服务

import { Injectable } from '@angular/core';

@Injectable()
export class MailService {
  messages: string[] = [
    '天之骄子,加入修仙之路群',
    'Shadows,加入修仙之路群',
    'Keriy,加入修仙之路群'
  ];
}

更新 AppComponent 组件

import {Component} from '@angular/core';
import {MailService} from "./mail.service";

@Component({
  selector: 'app-root',
  template: `
    

{{title}}

  • {{i}} - {{message}}
` }) export class AppComponent { title = 'Hello, Angular'; constructor(private mailService: MailService) {} }

在 AppComponent 组件的模板中,我们使用 let item of items; 语法迭代数组中的每一项,另外我们使用 index as i 用来访问数组中每一项的索引值。除了 index 外,我们还可以获取以下的值:

  • first: boolean - 若当前项是可迭代对象的第一项,则返回 true
  • last: boolean - 若当前项是可迭代对象的最后一项,则返回 true
  • even: boolean - 若当前项的索引值是偶数,则返回 true
  • odd: boolean - 若当前项的索引值是奇数,则返回 true

需要注意的是,*ngFor 中的 * 号是语法糖,表示结构指令。因为该语法最终会转换成:


  
  • ...
  • 除了 *ngFor 外,常用的结构指令还有 *ngIf*ngSwitchCase 指令。

    第七节 - 使用 Input 装饰器

    为了让我们能够开发更灵活的组件,Angular 为我们提供了 Input 装饰器,用于定义组件的输入属性。

    使用 Input 装饰器

    更新 SimpleFormComponent 组件

    import {Component, OnInit,Input} from '@angular/core';
    
    @Component({
      selector: 'app-simple-form',
      template: `
        
    {{message}}
    `, styles: [] }) export class SimpleFormComponent implements OnInit { @Input() message: string; // ... }

    更新 AppComponent 组件

    import {Component} from '@angular/core';
    import {MailService} from "./mail.service";
    
    @Component({
      selector: 'app-root',
      template: `
        

    {{title}}

    ` }) export class AppComponent { title = 'Hello, Angular'; constructor(private mailService: MailService) {} }

    在 AppComponent 组件模板中,我们使用 [message]="message" 属性绑定的语法,实现数据传递。即把数据从 AppComponent 组件,传递到 SimpleFormComponent 组件中。

    需要注意的是,当 SimpleFormComponent 组件类的属性名称不是 message 时,我们需要告诉 Angular 如何进行属性值绑定,具体如下:

    export class SimpleFormComponent implements OnInit {
      @Input('message') msg: string;
      // ...
    }

    不过一般不推荐这样做,尽量保持名称一致。

    第八节 - 使用双向绑定

    使用过 AngularJS 1.x 的同学,应该很熟悉 ng-model 指令,通过该指令我们可能方便地实现数据的双向绑定。而在 Angular 中,我们是通过 ngModel 指令,来实现双向绑定。

    使用双向绑定

    引入 FormsModule

    import {FormsModule} from "@angular/forms";
    
    @NgModule({
      // ...
      imports: [
        BrowserModule,
        FormsModule
      ],
      // ...
    })
    export class AppModule { }

    使用 ngModel 指令

    @Component({
      selector: 'app-simple-form',
      template: `
        
    {{message}}
    `, styles: [] }) export class SimpleFormComponent implements OnInit { // ...}

    上面示例中,我们使用 [(ngModel)]="message" 语法实现数据的双向绑定。该语法也称作 Banana in the Box 语法,即香蕉在盒子里 (比较形象生动,记忆该语法)。

    除了使用双向绑定,我们也可以通过 ngModel 指令,实现单向数据绑定,如 [ngModel]="message"

    第九节 - 使用 Output 装饰器

    Output 装饰器的作用是用来实现子组件将信息,通过事件的形式通知到父级组件。

    在介绍 Output 属性装饰器前,我们先来介绍一下 EventEmitter 这个幕后英雄:

    let numberEmitter: EventEmitter = new EventEmitter(); 
    numberEmitter.subscribe((value: number) => console.log(value));
    numberEmitter.emit(10);

    接下来我们来介绍如何使用 Output 装饰器。

    使用 Output 装饰器

    更新 SimpleFormComponent 组件

    import {Component, OnInit, Input, Output, EventEmitter} from '@angular/core';
    
    @Component({
      selector: 'app-simple-form',
      template: `
        
    {{message}}
    `, styles: [] }) export class SimpleFormComponent implements OnInit { @Input() message: string; @Output() update = new EventEmitter<{text: string}>(); ngOnInit() { } }

    更新 MailService 服务

    import {Injectable} from '@angular/core';
    
    @Injectable()
    export class MailService {
    
      messages: Array<{id: number, text: string}> = [
        {id: 0, text: '天之骄子,加入修仙之路群'},
        {id: 1, text: 'Shadows,加入修仙之路群'},
        {id: 2, text: 'Keriy,加入修仙之路群'}
      ];
    
      update(id, text) {
        this.messages = this.messages.map(msg => {
          return msg.id === id ? {id, text} : msg;
        });
      }
    }

    更新 AppComponent 组件

    import {Component} from '@angular/core';
    import {MailService} from "./mail.service";
    
    @Component({
      selector: 'app-root',
      template: `
        

    {{title}}

    • {{message.text}}
    ` }) export class AppComponent { title = 'Hello, Angular'; onUpdate(id, text) { this.mailService.update(id, text); } constructor(private mailService: MailService) {} }

    上面示例中,我们仍然使用 (eventName) 事件绑定的语法,监听我们自定义的 update 事件。当在 SimpleFormComponent 组件中修改 input 输入框的文本消息后,点击更新按钮,将会调用 AppComponent 组件类中的 onUpdate() 方法,更新对应的信息。

    第十节 - 组件样式

    在 Angular 中,我们可以在设置组件元数据时通过 stylesstyleUrls 属性,来设置组件的内联样式和外联样式。

    使用 styles 属性

    import {Component, OnInit, Input, Output, EventEmitter} from '@angular/core';
    
    @Component({
      selector: 'app-simple-form',
      template: `
        ...
      `,
      styles: [`
       :host { margin: 10px; }
       
       input:focus { font-weight: bold;}
      `
      ]
    })
    export class SimpleFormComponent implements OnInit {
      @Input() message: string;
      @Output() update = new EventEmitter<{text: string}>();
    
      ngOnInit() {}
    }

    上面示例中 :host 表示选择宿主元素,即 AppComponent 组件模板中的 app-simple-form 元素。

    用过 AngularJS 1.x 的同学,对 ng-class 应该很熟悉,通过它我们能够根据条件,为元素动态的添加或移除对应的样式。在 Angular 中,对应的指令是 ngClass 。接下来我们来看一下,ngClass 指令的具体应用。

    使用 ngClass 指令

    ngClass 指令接收一个对象字面量,对象的 key 是 CSS class 的名称,value 的值是 truthy/falsy 的值,表示是否应用该样式。

    @Component({
      selector: 'app-simple-form',
      template: `
        
    {{message}}
    `, styles: [` :host { margin: 10px; } .mousedown { border: 2px solid green; } input:focus { font-weight: bold; outline: none;} ` ] }) export class SimpleFormComponent implements OnInit { isMousedown: boolean; // ... }

    ngClass 指令用法

    
    
    This is never bordered
    This is always bordered
    Using object literal. Border {{ isBordered ? "ON" : "OFF" }}
    Class names contains dashes must use single quote
    This will always have a blue background and round corners

    除了 ngClass 指令外,Angular 还为我们提供了 ngStyle 指令。

    使用 ngStyle 指令

    ngStyle 指令让我们可以方便得通过 Angular 表达式,设置 DOM 元素的 CSS 属性。

    ngStyle 指令用法

    Uses fixed white text on blue background

    需要注意的是, background-color 需要使用单引号,而 color 不需要。这其中的原因是,ng-style 要求的参数是一个 Javascript 对象,color 是一个有效的 key,而 background-color 不是一个有效的 key ,所以需要添加 ''

    对于一些场合,我们也可以直接利用 Angular 属性绑定的语法,来快速设置元素的样式。

    • 设置元素的背景颜色
    Use fixed yellow background
    • 设置元素的字体大小
    
    
    Red Text

    我有话说

    应该如何引入第三方 UI 库,如 bootstrap

    若要引入第三方 UI 库,可以在 .angular-cli.json 文件中,配置对应的样式文件地址,具体如下:

    {
      "apps": {
         "styles": [
             "styles.css",
             "../node_modules/bootstrap/dist/css/bootstrap.min.css"
          ]
      }
    }

    除了本系列教程外,还有其它入门的资料么?

    本系列教程的主要目的是让初学者对 Angular 的相关基础知识,有一定的了解。除了本系列教程外,初学者还可以参考以下教程:

    • Angular 4 快速入门
    • Angular 4 表单快速入门
    • Angular 4 指令快速入门
    • Angular 4.x 路由快速入门
    • Angular 4 依赖注入教程之一 依赖注入简介(共八节)
    • Angular 4 组件学习线路(仅供参考)

    你可能感兴趣的:(angular2,angularjs)