Angular中的组件基础


本文作者: jsweibo

本文链接: https://jsweibo.github.io/2019/12/06/Angular%E4%B8%AD%E7%9A%84%E7%BB%84%E4%BB%B6%E5%9F%BA%E7%A1%80/

摘要

本文主要讲述了:

  1. 新建组件
  2. 使用组件
  3. 父组件向子组件传递数据
  4. 子组件向父组件发射自定义事件
  5. 单向数据流
  6. 插槽
  7. 在根模块中使用子模块中的组件

正文

注意:

  1. 任何一个组件都必须隶属于一个领域模块
  2. 想要在根模块中使用子模块中的组件,必须让对应的子模块先输出对应的组件,然后在根模块内引用对应的子模块

新建组件

示例:

  1. src/app/目录内创建名为components/job的目录
  2. src/app/components/job/目录内创建job.component.cssjob.component.htmljob.component.tsjob.component.spec.ts
  3. src/app.module.ts中引用JobComponent
1
2
3
#!/usr/bin/env bash

ng generate component components/job

使用组件

  1. 一个组件的模板文件中,可以有多个顶层元素

示例:

my-angular/src/app/app.module.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { FooComponent } from './pages/foo/foo.component';
import { BarComponent } from './pages/bar/bar.component';

import { RegisterModule } from './modules/register/register.module';

import { SalaryPipe } from './pipes/salary.pipe';
import { IsVipPipe } from './pipes/is-vip.pipe';

import { LoginFormComponent } from './components/login-form/login-form.component';
import { JobComponent } from './components/job/job.component';

@NgModule({
declarations: [
AppComponent,
FooComponent,
BarComponent,
SalaryPipe,
IsVipPipe,
LoginFormComponent,
JobComponent,
],
imports: [
BrowserModule,
FormsModule,
ReactiveFormsModule,
HttpClientModule,
AppRoutingModule,
RegisterModule,
],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}

my-angular/src/app/app.component.html

1
2
3
<div *ngFor="let item of jobList; trackBy: jobTrackBy">
<app-job></app-job>
</div>

my-angular/src/app/app.component.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import { Component } from '@angular/core';
import { Job } from './types/Job';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
jobList: Job[] = [
{
jobId: 1,
jobName: '会计',
salary: 1000,
companyName: 'A有限责任公司',
isVip: 1,
},
{
jobId: 2,
jobName: '销售',
salary: 2000,
companyName: 'B有限责任公司',
isVip: 0,
},
{
jobId: 3,
jobName: '主管',
salary: 3000,
companyName: 'B有限责任公司',
isVip: 0,
},
];

jobTrackBy(index: number, item: Job) {
return item.jobId;
}
}

父组件向子组件传递数据

使用Input()装饰器来装饰属性

示例:

my-angular/src/app/app.component.html

1
2
3
<div *ngFor="let item of jobList; trackBy: jobTrackBy">
<app-job [job]="item"></app-job>
</div>

my-angular/src/app/components/job/job.component.html

1
2
3
4
5
6
<div>
<div>{{ job.jobId }}</div>
<div>{{ job.jobName }}</div>
<div>{{ job.salary }}</div>
<div>{{ job.companyName }}</div>
</div>

my-angular/src/app/components/job/job.component.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import { Component, OnInit, Input } from '@angular/core';
import { Job } from 'src/app/types/Job';

@Component({
selector: 'app-job',
templateUrl: './job.component.html',
styleUrls: ['./job.component.css'],
})
export class JobComponent implements OnInit {
@Input() job: Job = {
jobId: 0,
jobName: '',
salary: 0,
companyName: '',
};

constructor() {}

ngOnInit(): void {}
}

子组件向父组件发射自定义事件

使用Output()装饰器来装饰自定义事件

示例:

my-angular/src/app/app.component.html

1
2
3
<div *ngFor="let item of jobList; trackBy: jobTrackBy">
<app-job [job]="item" (clickEvent)="onClick($event)"></app-job>
</div>

my-angular/src/app/app.component.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import { Component } from '@angular/core';
import { Job } from './types/Job';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
jobList: Job[] = [
{
jobId: 1,
jobName: '会计',
salary: 1000,
companyName: 'A有限责任公司',
isVip: 1,
},
{
jobId: 2,
jobName: '销售',
salary: 2000,
companyName: 'B有限责任公司',
isVip: 0,
},
{
jobId: 3,
jobName: '主管',
salary: 3000,
companyName: 'B有限责任公司',
isVip: 0,
},
];

jobTrackBy(index: number, item: Job) {
return item.jobId;
}

onClick(jobId: number) {
console.log(jobId);
}
}

my-angular/src/app/components/job/job.component.html

1
2
3
4
5
6
<div (click)="onClick()">
<div>{{ job.jobId }}</div>
<div>{{ job.jobName }}</div>
<div>{{ job.salary }}</div>
<div>{{ job.companyName }}</div>
</div>

my-angular/src/app/components/job/job.component.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { Job } from 'src/app/types/Job';

@Component({
selector: 'app-job',
templateUrl: './job.component.html',
styleUrls: ['./job.component.css'],
})
export class JobComponent implements OnInit {
@Input() job: Job = {
jobId: 0,
jobName: '',
salary: 0,
companyName: '',
};

@Output() clickEvent = new EventEmitter<number>();

onClick() {
this.clickEvent.emit(this.job.jobId);
}

constructor() {}

ngOnInit(): void {}
}

单向数据流

子组件不能直接变更由父组件传入的数据,而是应该向父组件发射自定义事件,通知父组件变更

自始至终,数据都保存在父组件中,数据变更也发生在父组件中

若:

  1. 父组件传递给子组件的属性名为x
  2. 子组件发射给父组件的自定义事件名为xChange

则:

在父组件的模板文件中,子组件的属性绑定和事件监听可以写成[(x)]的形式

插槽

示例:

my-angular/src/app/app.component.html

1
2
3
4
<app-login-form>
<div header>hello, jsweibo</div>
<div footer>bye, jsweibo</div>
</app-login-form>

my-angular/src/app/components/login-form/login-form.component.html

1
2
3
4
5
6
7
8
9
<div>
<div class="form-header">
<ng-content select="[header]"></ng-content>
</div>
<div class="form-body"></div>
<div class="form-footer">
<ng-content select="[footer]"></ng-content>
</div>
</div>

在根模块中使用子模块中的组件

示例:

my-angular/src/app/modules/register/register.module.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';

import { RegisterRoutingModule } from './register-routing.module';
import { ResetPasswordComponent } from './pages/reset-password/reset-password.component';
import { UserAgreementComponent } from './components/user-agreement/user-agreement.component';

@NgModule({
declarations: [ResetPasswordComponent, UserAgreementComponent],
imports: [CommonModule, RegisterRoutingModule],
exports: [UserAgreementComponent],
})
export class RegisterModule {}

my-angular/src/app/app.component.html

1
<app-user-agreement></app-user-agreement>

参考资料

本文作者: jsweibo

本文链接: https://jsweibo.github.io/2019/12/06/Angular%E4%B8%AD%E7%9A%84%E7%BB%84%E4%BB%B6%E5%9F%BA%E7%A1%80/


本文对你有帮助?请支持我


支付宝
微信