本文已参与「新人创作礼」活动,一起开启掘金创作之路。
组件交互
- 通过输入型绑定把数据从父组件传到子组件
// hero-child.component.ts
@Input() hero!: Hero;
@Input('master') masterName = '';// 起别名,但是不推荐
// hero-parent.component.ts
<app-hero-child
*ngFor="let hero of heroes"
[hero]="hero"
[master]="master">
</app-hero-child>
- 通过 setter 截听输入属性值的变化
@Input()
get name(): string { return this._name; }
set name(name: string) {
this._name = (name && name.trim()) || '<no name set>';
}
private _name=''
- 用ngOnChanges()监听属性值的变化
ngOnChanges(changes: SimpleChanges) {
for (const propName in changes) {
const changedProp = changes[propName];
const to = JSON.stringify(changedProp.currentValue);
if (changedProp.isFirstChange()) {
console.log(`Initial value of ${propName} set to ${to}`);
} else {
const from = JSON.stringify(changedProp.previousValue);
console.log(`${propName} changed from ${from} to ${to}`);
}
}
}
- 父组件监听子组件的事件
// child
template: `
<h4>{{name}}</h4>
<button (click)="vote(true)" [disabled]="didVote">Agree</button>
<button (click)="vote(false)" [disabled]="didVote">Disagree</button>
`
export class VoterComponent {
@Input() name = '';
@Output() voted = new EventEmitter<boolean>(); // boolean 为传递对象的类型
didVote = false;
vote(agreed: boolean) {
this.voted.emit(agreed);
this.didVote = true;
}
}
// parent
template: `
<h2>Should mankind colonize the Universe?</h2>
<h3>Agree: {{agreed}}, Disagree: {{disagreed}}</h3>
<app-voter
*ngFor="let voter of voters"
[name]="voter"
(voted)="onVoted($event)"> // 以$event为传递的值
</app-voter>
`
export class VoteTakerComponent {
agreed = 0;
disagreed = 0;
voters = ['Narco', 'Celeritas', 'Bombasto'];
onVoted(agreed: boolean) { // agreed 为攒底的对象
if (agreed) {
this.agreed++;
} else {
this.disagreed++;
}
}
}
5.父组件调用子组件方法
template: `
<h3>Countdown to Liftoff (via local variable)</h3>
<button (click)="timer.start()">Start</button>
<button (click)="timer.stop()">Stop</button>
<div class="seconds">{{timer.seconds}}</div>
<app-countdown-timer #timer></app-countdown-timer>
`
// 2.
@ViewChild(CountdownTimerComponent) private timerComponent!: CountdownTimerComponent;
start() { this.timerComponent.start(); }
组件样式
拥有样式模块化功能,不会被模板嵌入的组件所继承,也不会被通过内容投影(如 ng-content)嵌进来的组件所继承。
特性:
- 可以使用对每个组件最有意义的 CSS 类名和选择器。
- 类名和选择器是局限于该组件的,它不会和应用中其它地方的类名和选择器冲突。
- 组件的样式不会因为别的地方修改了样式而被意外改变。
- 可以让每个组件的 CSS 代码和它的 TypeScript、HTML 代码放在一起,这将促成清爽整洁的项目结构。
- 以后还可以修改或移除组件的 CSS 代码,而不用遍历整个应用来看它有没有在别处用到。
特殊的选择器
:host
被称为宿主元素,模板会渲染到其中。:host 伪类选择器可用于创建针对宿主元素自身的样式,而不是针对宿主内部的那些元素。
::host-context
以某些来自宿主的祖先元素为条件来决定是否要应用某些样式。
:host-context(.active) { // 当模板的父元素为 class 时触发。
font-style: italic;
}
::ng-deep
任何带有 ::ng-deep 的样式都会变成全局样式。如果使用的话需要带上 :host 以防止污染其他组件。