生命周期
紅色的方法只會(huì)運(yùn)行一次;綠色的方法可以運(yùn)行多次濒旦。
從根組件開(kāi)始檢查株旷;帶check的生命周期勾子在啟動(dòng)變更檢測(cè)的時(shí)候,除了OnPush聲明的組件外尔邓,其它都會(huì)調(diào)用相應(yīng)的帶check的勾子晾剖。
@ViewChild('child1')用來(lái)在父組件中引用子組件的方法,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="調(diào)用子組件的方法" (click)="child2.greeting('jerry')">
投影
<ng-content></ng-content>放置在子組件中梯嗽,用來(lái)給父組件在子組件中投影相應(yīng)HTML代碼
生命周期實(shí)戰(zhàn)
給商品詳情面頁(yè)增加評(píng)論功能
在angular中永遠(yuǎn)是用數(shù)據(jù)去控制DOM頁(yè)面齿尽,通過(guò)數(shù)據(jù)綁定,來(lái)改變屬性灯节,從而改變頁(yè)面循头。
- 添加評(píng)論功能
- 實(shí)現(xiàn)評(píng)論的現(xiàn)實(shí)隱藏
- 計(jì)算星級(jí)評(píng)論的平均分
用到知識(shí)點(diǎn):
- 雙向綁定
- Input 和Output裝飾器
- EventEmitter對(duì)象 的emit方法
- ngOnChange變更檢測(cè)勾子(生命周期)
雙向綁定中,子組件用@Input裝飾的屬性如rating;用@Output裝飾的屬性如ratingChange(通過(guò)EventEmitter對(duì)象 的emit方法發(fā)射出來(lái)的屬性)炎疆;在父組中調(diào)用雙向綁定時(shí)可以直接寫(xiě)成[(rating)]="newRating" 這樣就可以改變父組件中的newRating屬性的值卡骂。詳見(jiàn)代碼;
商品詳情頁(yè)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; //定義了一個(gè)Product類(lèi)型的本地屬性product(單個(gè)商品)
comments: CommentArray[];
newRating: number = 5;//新的星級(jí)
newComment: string = '';//新的評(píng)價(jià)內(nèi)容
isCommentHidden: boolean = true;//設(shè)置評(píng)價(jià)文本區(qū)域隱藏屬性
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);
/*計(jì)算平均的rating*/
//reduce方法通過(guò)遍歷comments數(shù)組磷雇,初始值sum為0偿警,每遍歷一次sum值+ CommentItem.rating的值,再賦值給sum
let sum = this.comments.reduce((sum, CommentItem) => sum + CommentItem.rating, 0);
this.product.rating = sum / this.comments.length;
/*恢復(fù)初始的值*/
this.newComment = null;
this.newRating = 5;
this.isCommentHidden = true;
}
}
商品詳情頁(yè)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">
<!--評(píng)論功能-->
<div>
<button class="btn btn-success" (click)="isCommentHidden = !isCommentHidden">點(diǎn)擊評(píng)論</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>
<!--評(píng)論功能-->
<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>
星級(jí)評(píng)價(jià)組件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;//星級(jí)等級(jí)
private stars:boolean[];//通過(guò)實(shí)心和空心判斷數(shù)量
@Output()
private ratingChange:EventEmitter<number> = new EventEmitter();//將變化的星級(jí)評(píng)價(jià)發(fā)射出去
@Input()
private readonly:boolean = true ;//控制星星的只讀屬性
constructor() { }
ngOnInit() {
}
/*變更檢測(cè)唯笙,把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的值發(fā)射給父組件
this.ratingChange.emit(this.rating);
}
}
}
星級(jí)評(píng)價(jià)組件模板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>