生命周期
红色的方法只会运行一次;绿色的方法可以运行多次。
从根组件开始检查;带check的生命周期勾子在启动变更检测的时候,除了OnPush声明的组件外,其它都会调用相应的带check的勾子。
@ViewChild('child1')用来在父组件中引用子组件的方法,child1为子组件的模 板本地变量名
新建 child组件
ng g component child
child组件
//组件
greeting(name:string){
console.log('hello '+name);
}
app父组件
import {Component, OnInit, ViewChild} from '@angular/core';
import {ChildComponent} from "./child/child.component";
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
@ViewChild('child1')
child1: ChildComponent;
ngOnInit() {
this.child1.greeting('Tom');
}
}
app组件模板
<app-child #child1></app-child>
<app-child #child2></app-child>
<input type="button" value="调用子组件的方法" (click)="child2.greeting('jerry')">
投影
<ng-content></ng-content>放置在子组件中,用来给父组件在子组件中投影相应HTML代码
生命周期实战
给商品详情面页增加评论功能
在angular中永远是用数据去控制DOM页面,通过数据绑定,来改变属性,从而改变页面。
- 添加评论功能
- 实现评论的现实隐藏
- 计算星级评论的平均分
用到知识点:
- 双向绑定
- Input 和Output装饰器
- EventEmitter对象 的emit方法
- ngOnChange变更检测勾子(生命周期)
双向绑定中,子组件用@Input装饰的属性如rating;用@Output装饰的属性如ratingChange(通过EventEmitter对象 的emit方法发射出来的属性);在父组中调用双向绑定时可以直接写成[(rating)]="newRating" 这样就可以改变父组件中的newRating属性的值。详见代码;
商品详情页product-detail.component.ts中
import {Component, OnInit} from '@angular/core';
import {ActivatedRoute} from "@angular/router";
import {CommentArray, Product, ProductService} from "../shared/product.service";
@Component({
selector: 'app-product-detail',
templateUrl: './product-detail.component.html',
styleUrls: ['./product-detail.component.css']
})
export class ProductDetailComponent implements OnInit {
product: Product; //定义了一个Product类型的本地属性product(单个商品)
comments: CommentArray[];
newRating: number = 5;//新的星级
newComment: string = '';//新的评价内容
isCommentHidden: boolean = true;//设置评价文本区域隐藏属性
constructor(private routeInfo: ActivatedRoute,
private productService: ProductService) {
}
ngOnInit() {
let productId: number = this.routeInfo.snapshot.params['productId'];
this.product = this.productService.getProduct(productId);
this.comments = this.productService.getCommentForProductId(productId);
}
addComment() {
let comment = new CommentArray(0, this.product.id, new Date().toISOString(), 'song.qin',
this.newRating, this.newComment);
this.comments.unshift(comment);
/*计算平均的rating*/
//reduce方法通过遍历comments数组,初始值sum为0,每遍历一次sum值+ CommentItem.rating的值,再赋值给sum
let sum = this.comments.reduce((sum, CommentItem) => sum + CommentItem.rating, 0);
this.product.rating = sum / this.comments.length;
/*恢复初始的值*/
this.newComment = null;
this.newRating = 5;
this.isCommentHidden = true;
}
}
商品详情页product-detail.component.html中
<div class="thumbnail">
<img src="http://placehold.it/820x230" alt="">
<div>
<h4 class="pull-right">{{product.price}}元</h4>
<h4>{{product.title}}</h4>
<p>{{product.desc}}</p>
</div>
<div>
<p class="pull-right">{{comments.length}}</p>
<p>
<app-stars [rating]="product.rating"></app-stars>
</p>
</div>
</div>
<div class="well">
<!--评论功能-->
<div>
<button class="btn btn-success" (click)="isCommentHidden = !isCommentHidden">点击评论</button>
</div>
<div [hidden]="isCommentHidden">
<div>
<app-stars [(rating)]="newRating" [readonly]="false"></app-stars>
</div>
<div>
<textarea name="innerContent" [(ngModel)]="newComment"></textarea>
</div>
<div>
<button class="btn" (click)="addComment()">提交</button>
</div>
</div>
<!--评论功能-->
<div class="row" *ngFor="let comment of comments">
<hr>
<div class="col-md-12">
<app-stars [rating]="comment.rating"></app-stars>
<span>{{comment.user}}</span>
<span class="pull-right">{{comment.timestamp}}</span>
<p></p>
<p>{{comment.content}}</p>
</div>
</div>
</div>
星级评价组件stars.component.ts中
import {Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges} from '@angular/core';
@Component({
selector: 'app-stars',
templateUrl: './stars.component.html',
styleUrls: ['./stars.component.css']
})
export class StarsComponent implements OnInit,OnChanges {
@Input()
private rating:number = 0;//星级等级
private stars:boolean[];//通过实心和空心判断数量
@Output()
private ratingChange:EventEmitter<number> = new EventEmitter();//将变化的星级评价发射出去
@Input()
private readonly:boolean = true ;//控制星星的只读属性
constructor() { }
ngOnInit() {
}
/*变更检测,把rating属性样式重置*/
ngOnChanges(changes: SimpleChanges): void {
this.stars=[];
for(let i = 1;i<=5;i++){
this.stars.push(i>this.rating);
}
}
clickStar(index:number){
if(!this.readonly){
this.rating = index + 1;
//this.ngOnInit();
//所新变化的rating的值发射给父组件
this.ratingChange.emit(this.rating);
}
}
}
星级评价组件模板stars.component.html中
<p>
<span *ngFor="let star of stars;let i = index;" class="glyphicon glyphicon-star"
[class.glyphicon-star-empty]="star" (click)="clickStar(i)"></span>
<span>{{rating | number:'1.0-1'}}星</span>
</p>