【Angular】组件
创建组件
Angular CLI 创建
在项目根目录下运行 ng generate component <component-name>
命令,<component-name>
为组件名称
手动创建
<component-name>.component.ts
文件基本内容
import { Component } from "@angular/core"; // 引入 Angular 核心模块
// 组件用 @Component 装饰器
@Component({
selector: "app-component-overview", // 指定组件填充目标选择器
templateUrl: "./component-overview.component.html", // 指定组件的HTML模板路径,与 template 互斥
template: `<div><div>`, // 组件HTML模板,与 templateUrl 互斥
styleUrls: ["./component-overview.component.css"], // 指定组件 css 文件路径
styles: ["h1 { font-weight: normal; }"], // 直接在组件内指定样式
})
export class ComponentOverviewComponent {}
@Component()
声明一个组件
示例
@Component({
selector: "app-hero-list",
templateUrl: "./hero-list.component.html",
styleUrls: ["./hero-list.component.css"],
providers: [HeroService],
})
export class HeroListComponent implements OnInit {
/* . . . */
}
配置项
selector:是一个 CSS 选择器,它会告诉 Angular,一旦在模板 HTML 中找到了这个选择器对应的标签,就创建并插入该组件的一个实例。 比如,如果应用的 HTML 中包含
<app-hero-list></app-hero-list>
,Angular 就会在这个标签中插入一个HeroListComponent
实例的视图。templateUrl:该组件的
HTML
模板文件相对于这个组件文件的地址。 另外,你还可以用 template 属性的值来提供内联的HTML
模板。 这个模板定义了该组件的宿主视图。providers:注入服务。
组件生命周期
每个接口都有唯一的一个钩子方法,它们的名字是由接口名再加上 ng
前缀构成的。
执行顺序
ngOnChanges()
在ngOnInit()
之前以及所绑定的一个或多个输入属性的值发生变化时都会调用。当
Angular
设置或重新设置数据绑定的输入属性时响应,无法监听引用类型具体值的变化。ngOnInit()
在第一轮ngOnChanges()
完成之后调用,只调用一次。ngDoCheck()
紧跟在每次执行变更检测时的ngOnChanges()
和 首次执行变更检测时的ngOnInit()
后调用。ngAfterContentInit()
第一次ngDoCheck()
之后调用,只调用一次。ngAfterContentChecked()
ngAfterContentInit()
和每次ngDoCheck()
之后调用ngAfterViewInit()
第一次ngAfterContentChecked()
之后调用,只调用一次。ngAfterViewChecked()
ngAfterViewInit()
和每次ngAfterContentChecked()
之后调用。ngOnDestroy()
在 Angular 销毁指令或组件之前立即调用。
组件通信
父向子传递属性
父组件将自身值传递给子组件,子组件用 @Input
接收
- 父组件设置
<app-child [hero]="selectedHero"></app-child>
- 子组件设置
import { Component, Input } from '@angular/core'; // 需要引入@Input装饰器
export class componentName {
// 1.直接接收
@Input() hero: Hero;
// 2.设置getter、setter
private _valueName; // 需要设置一个变量来接收
@Input()
get hero() { // 每次读取hero值就会触发
// doSomething...
return this._valueName;
}
set hero(name) { // 设置hero值时触发
// doSomething...
this._valueName = name;
}
}
自定义事件
- 父组件设置
<app-child (voted)="onVoted($event)"></app-child>
onVoted(name) {
// doSomething...
}
- 子组件设置
@Output()
必须是 EventEmitter
类型,它是 @angular/core
中用来发出自定义事件的类。
import { Output, EventEmitter } from "@angular/core";
export class HeroDetailComponent implements OnInit {
@Output() voted = new EventEmitter(); // 实例化一个事件发射器
ngOnInit() {
this.voted.emit("here is child");
}
}
父组件访问子组件属性
本地变量
父组件的类无法通过本方法读取子组件的属性值或调用其方法
- 父组件设置
<app-child #childVm></app-child>
<button (click)="clickBtn(childVm)">获取子组件</button>
ViewChild
- 父组件设置
import { ViewChild } from '@angular/core'; // 引入 ViewChild 装饰器
import { HeroDetailComponent } from '../hero-detail/hero-detail.component'; // 引入子组件
export class HeroesComponent implements OnInit {
@ViewChild(HeroDetailComponent)
private childComponent: HeroDetailComponent;
ngOnInit() {
console.log(this.childComponent); // 与本地变量法获取的是同一个对象
}
}
服务通信
不同的组件(有无关系均可)引用同一个服务实现通信,通过事件传递
- 服务
message.service.ts
import { Injectable } from "@angular/core";
@Injectable({
providedIn: "root",
})
export class MessageService {
serviceData = [];
add(message: string) {
this.serviceData.push(message);
}
}
- A 组件
import { MessageService } from '../message.service';
export class componentA {
constructor(private messageService: MessageService) { } // 在constructor函数上注册服务
ngOnInit() {
console.log(this.messageService.serviceData)
}
add() {
this.messageService.add('from A');
}
}
- B 组件
import { MessageService } from '../message.service';
export class componentB {
constructor(private messageService: MessageService) { } // 在constructor函数上注册服务
ngOnInit() {
console.log(this.messageService.serviceData)
}
add() {
this.messageService.add('from B');
}
}
组件样式
定义方式
- 在装饰器的
styleUrls
属性中指定文件路径 - 在装饰器的
styles
属性中直接定义 - 在装饰器的
template
属性中定义<link>
标签 - 在
html
文件中以<style>
标签形式定义 - 在
css
文件中使用@import
引入其他css
文件 - 在
angular.json
文件中的styles
内注册全局样式
@Component({
styleUrls: ["./component-overview.component.css"], // 指定组件 css 文件路径
styles: ["h1 { font-weight: normal; }"], // 直接在组件内指定样式
})
export class ComponentA {}
特殊选择器
:host
选择宿主元素,即父组件中使用组件所用的标签<componentA></componentA>
/* 设置宿主元素的样式 */
:host {
}
/* 只有当宿主元素有active的类名时才有效 */
:host(.active) {
}
:host-context
在当前组件宿主元素的祖先节点中查找CSS 类
/* 只有当某个祖先元素有 CSS 类 theme-light 时,才会把样式应用到组件内部的所有 <h2> 元素中 */
:host-context(.theme-light) h2 {
}
::ng-deep
任何带有::ng-deep
的样式都会变成全局样式