跟着项目走
项目结构
MVC 开发模式 : 三层结构 View视图层 .html,Control 逻辑处理层 .ts,Module 数据模型层 .ts
新建数据层 .ts 文件 如 recipes 下面手动创建的 recipe.module.ts
recipe.module.ts 数据模型,只在组件 recipes, recipe-list, recipe-item, recipe-detail 里能用到,所以我们把它放入 最外边的 recipes 文件夹中,像 ingredient.module.ts 数据模型所有自建控件都要用,那就在 app folder 下面新建 "share" folder
export class Recipe {
public name: string;
public description: string;
public imagePath: string;
constructor(name: string, desc: string, imagePath: string) {
//构造函数
this.name = name;
this.description = desc;
this.imagePath = imagePath;
}
}
上面的一大堆可以简化写为:
export class Recipe{
//注意这里的class 名开头字母要大写
constructor(public name: string, public description: string, public imagePath: string) {}
}
如何将 数据模型 recipe.module.ts 和组件 recipe 组件进行结合呢?
在 recipes-list.component.ts 里
引用 recipe.module.ts 文件里的 class 创建 recipe 对象: import { Recipe } from '../recipe.module';
Tips: 如果我们不知道怎么去算这个相对路径,那么就干脆这么写 import { Ingredient } from 'src/app/......XX.module';
recipes: Recipe[] = [
new Recipe( "name", "desc", "https://i.ytimg.com/vi/S4QsIz9eLdo/hqdefault.jpg?sqp=-oaymwEYCKgBEF5IVfKriqkDCwgBFQAAiEIYAXAB&rs=AOn4CLADbJI8vPDsx9RUrKlyd27mp46mYw" )
];
此时就可以在 recipes-list.component.ts 里调取数据了 {{recipes[0].name}}
父组件 recipe-list code, 此时它要把对象做一个循环将数据传递给子组件 recipe item:
<app-recipes-item *ngFor="let recipe of recipes; let i=index" [item]="recipe" [index]="i"></app-recipes-item>
这里的 recipes 是在 父组件里定义的数组
子组件 recipe item code
<div class="row" [ngStyle]="{backgroundColor: index%2 === 1? '#e0e0e0':'#eee'}">
<div class="col-4"><a href=""><img [src]="item.imagePath" class="img-fluid img-thumbnail mt-2"></a></div>
<div class="col-8 pt-2">
<p class="mb-0">名字:{{item.name}}</p>
<p>详情:{{item.description}} </p>
</div>
</div>
@Input() item;
@Input() index;
Tab 切换 Demo
- header 选出来的值传递到根组件中 (header 和 另外两个组件是平级的):
<li [ngClass]="{'nav-item': true, 'active': sellectTabName === 'recipe'}">
<a class="nav-link" href="#" (click)="onSelect('recipe')">食谱</a> </li>
<li [ngClass]="{'nav-item': true, 'active': sellectTabName === 'shopping-list'}">
<a class="nav-link" href="#" (click)="onSelect('shopping-list')">商品</a> </li>
import { Output, EventEmitter } from "@angular/core";
@Output() featureSelected: EventEmitter<string> = new EventEmitter<string>(); sellectTabName:string = "recipe";
onSelect(feature: string) {
this.sellectTabName = feature;
this.featureSelected.emit(feature);
} - app 根组件接收值
<app-header (featureSelected)="getFatherData($event)"></app-header>
<app-shoping-list *ngIf="sellectTab === 'recipe'"></app-shoping-list>
<app-recipes *ngIf="sellectTab === 'shopping-list'"></app-recipes>
sellectTab: string = "recipe";
getFatherData(msg: string) {
this.sellectTab = msg;
}
左边列表 list 点击列表其中一个item 右边显示详情 detail
- item 里的 a 标签 加事件 (click)="selectOne()"
import { Output, EventEmitter } from "@angular/core";
@Output() selectItem: EventEmitter<void> = new EventEmitter<void>();
selectOne() {
this.selectItem.emit();
}
这里其实它的父组件已经知道它选的是 index 了,所以向上传值没啥意义,就做一个传值的动作就行了。 - list 组件
<app-recipe-item *ngFor="let recipeEL of recipes; let i=index" [item]="recipeEL" [index]="i" (selectItem)="onRecipeSelected(recipeEL)"></app-recipe-item>
import { Output, EventEmitter } from "@angular/core";
import { Recipe } from "../recipe.module";
@Output() recipesWasSelected: EventEmitter<Recipe> = new EventEmitter<Recipe>();
onRecipeSelected(item: Recipe) {
this.recipesWasSelected.emit(item);
}
这里传的 选中的 整个的对象 "recipeEL" 再想上一层组件传递Tips: recipe.module.ts code:
export class Recipe {
//注意这里的class 名字自己取,但是开头字母要大写 constructor(public name: string, public description: string, public imagePath: string) {}
}在这个组件里放了 Recipe 对象列表
recipes: Recipe[] = [
new Recipe(
"name 千锋Web前端教程 1",
"desc 千锋Web前端教程:35 添加内容到组件 千锋Web前端教程:35 添加内容到组件",
"https://i.ytimg.com/vi/S4QsIz9eLdo/hqdefault.jpg?sqp=-oaymwEYCKgBEF5IVfKriqkDCwgBFQAAiEIYAXAB&rs=AOn4CLADbJI8vPDsx9RUrKlyd27mp46mYw"
),
new Recipe(
"2",
"1",
"https://ss0.baidu.com/73F1bjeh1BF3odCf/it/u=89521230,2695907708&fm=85"
)] - recipes 主组件
<app-recipe-list (recipesWasSelected)="selectedRecipe = $event"></app-recipe-list>
<app-recipe-detail *ngIf="selectedRecipe; else defaultInfo" [recipe]="selectedRecipe">
</app-recipe-detail>
<ng-template #defaultInfo>请选择一个食谱 <br>如果变量 selectedRecipe 不存在值, 这里的内容就会显示
</ng-template>
import { Recipe } from "./recipe.module";
selectedRecipe:Recipe;上面的其实是代替了 创建一个方法特意传参的冗余
(recipesWasSelected)="selectThisOne($event)"
selectThisOne(item:Recipe){
this.selectedRecipe = item;
} - Detail 详情组件
<p>{{item.description}}</p>
<img [src]="item.imagePath" alt="">
import { Recipe } from "../recipe.module";
@Input('recipe') item: Recipe;
子组件 add item 到父组件
- 子组件 上有两个文本框,输入提交后给父组件传值
<input id="name" #nameInput class="form-control" type="text">
<input id="amount" #amountInput class="form-control">
<button type="button" class="btn btn-success" (click)="onAddItem()">添加</button>
import { ViewChild, ElementRef, Output, EventEmitter } from "@angular/core";
import { Ingredient } from "../../../app/share/ingredient.module";
@ViewChild("nameInput") myNameInput: ElementRef;
@ViewChild("amountInput") myAmountInput: ElementRef;
@Output() ingredientAdd: EventEmitter = new EventEmitter< {name: string,amount: string}>();
onAddItem() {
const newIngredient = new Ingredient(this.myNameInput.nativeElement.value,this.myAmountInput.nativeElement.value);
this.ingredientAdd.emit(newIngredient);
} - 父组件
<app-shoping-edit (ingredientAdd) = "inIngredientAdd($event)"></app-shoping-edit>
import { Ingredient } from "../../app/share/ingredient.module";
ingredients: Ingredient[] = [ new Ingredient("土豆", 1) ];
inIngredientAdd(ingredient: Ingredient) {
this.ingredients.push(ingredient);
}