注:默认已有扎实的vue功底
循环体的根元素
template ng-container
<ng-container *ngIf="lessons">
<div class="lesson" *ngFor="let lesson of lessons">
<div class="lesson-detail">
{{lesson | json}}
</div>
</div>
</ng-container>
插槽
slot ngTemplateOutlet
<ng-container *ngTemplateOutlet="aaa; context: {{$implicit: '我是默认值,隐式定义,不需要赋值,对应let-name', diyValue: '我是自定义对象,需要赋值'}}" ></ng-container>
<ng-template #aaa let-name let-diyValue=”diyValue“>
默认值- {{name}}
赋值- {{diyValue}}
</ng-template>
#aaa
叫做模板引用变量
let-name
叫做模板输入变量
这里的理解是,
ng-template
插入对应的ng-container
的引用标记中,
即#aaa
插入到对应的*ngTemplateOutlet="aaa"
,
然后将变量``传入模板内,模板内接受变量进行赋值let-diyValue="xx"
,`
完了在模板作用域内使用该变量
{{diyValue}}`
自定义组件
引用
<ng-container *ngFor="let item of [1,2,3]; let idx=index">
<app-template-test [dTemplate]="tpl">
<ng-template #tpl>
<div>
<p>我进来看看{{item}}</p>
<p>我也进来康康{{idx}}</p>
</div>
</ng-template>
</app-template-test>
</ng-container>
ts
import { Component, OnInit, Input, TemplateRef } from '@angular/core';
@Component({
selector: 'app-template-test',
templateUrl: './template-test.component.html',
styleUrls: ['./template-test.component.css']
})
export class TemplateTestComponent implements OnInit {
@Input() dTemplate: TemplateRef<void>; // 接受外部模板
constructor() { }
ngOnInit(): void {
}
}
html
<div>
自己写的组件
blablabla
<ng-template #defaultContent>
我是默认显示的内容
</ng-template>
// 使用外部模板或者使用自定义模板
<ng-template [ngTemplateOutlet]="dTemplate || defaultContent"></ng-template>
</div>
组件传值
父传子
方法一 在父组件上设置子组件的属性【类似vue的props传参】
父组件绑定信息
<app-child childTitle="可设置子组件标题"></app-child>
子组件接收消息
import { Component, OnInit, Input } from '@angular/core';
@Input childTitle: string; // 类似vue的props接收参数
方法二 父组件调用子组件的方法
父组件触发消息 【类似vue的ref.methods的写法,区别是直接在模板调用】
<app-child #child></app-child> <button (click)="child.childPrint()"></button>
子组件接收消息
childPrint() {
alert("来自子组件的打印");
}
子传父
子组件向父组件传递信息
方法一 使用 EventEmitter
子组件使用 EventEmitter 传递消息
【类似vue的this. event)">点我`】
import { Component, OnInit, Output, EventEmitter } from '@angular/core';
...
@Output() initEmit = new EventEmitter<string>();
ngOnInit() {
this.initEmit.emit("子组件初始化成功");
}
...
父组件接收消息
<app-child (initEmit)="accept($event)"></app-child>
accept(msg:string) {
alert(msg);
}
方法二 使用 ViewChild
子组件提供传递参数的函数 【类似vue的ref操作,调用子组件方法来传数据】
sendInfo() {
return 'Message from child 1.';
}
// 父组件使用 ViewChild 触发并接收信息
<button (click)="getInfo()">获取子组件1号的信息</button>
import { Component, OnInit, ViewChild } from '@angular/core';
...
@ViewChild(ChildFirstComponent) private childcomponent: ChildFirstComponent;
getInfo() {
this.info = this.childcomponent.sendInfo();
}
非父子组件通信
方法一:server
缺点:需要双向的触发(发送信息 / 接收信息)
service.ts 一个公共的state文件
import { Component, Injectable, EventEmitter } from "@angular/core";
@Injectable() // 可注入的服务
export class myService {
public info: string = ""; // 相对于vue的state
constructor() {}
}
组件 1 向 service 传递信息
import { myService } from '../../service/myService.service'; // 在组件中引入服务
...
constructor(
public service: myService // 实例化服务
) { }
changeInfo() {
this.service.info = this.service.info + "1234"; // 修改服务
}
...
组件 2 从 service 获取信息
import { myService } from '../../service/myService.service';
...
constructor(
public service: myService
) { }
showInfo() {
alert(this.service.info);
}
...
方法二: 使用 BehaviorSubject
优点:真正的发布订阅模式,当数据改变时,订阅者也能得到响应
service
import { BehaviorSubject } from 'rxjs';
...
public messageSource = new BehaviorSubject<string>('Start');
changemessage(message: string): void {
this.messageSource.next(message);
}
组件调用 service 的方法传信息和接收信息
changeInfo() {
this.communication.changemessage('Message from child 1.');
}
ngOnInit() {
this.communication.messageSource.subscribe(Message => {
window.alert(Message);
this.info = Message;
});
}
其他的通信方式
- 路由传值
- cookie、session、storage
内容投影
ng-content 【类似vue的slot】
语法:
<ng-content select=".class,#id,select">
ng-content提供占位,select属性选择站位元素,相对于slot的名字。
创建组件
ng g c content-part-layout
ng g c content-part-a
ng g c content-part-b
content-part-layout
<p>content-part-layout works!</p>
<div>
<div>主页面</div>
<app-content-part-a></app-content-part-a>
<app-content-part-b></app-content-part-b>
<div> a嵌套b </div>
<app-content-part-a>
<div class="mydiv">我是a页面</div>
<app-content-part-b></app-content-part-b>
</app-content-part-a>
</div>
content-part-a
<p>content-part-a works!</p>
<ng-content select=".mydiv"></ng-content>
<ng-content select="app-content-part-b"></ng-content>
app.component.html
<!-- 内容投影,组件嵌套 -->
<app-content-part-layout></app-content-part-layout>
<div class="mydiv">我是a页面</div>
<app-content-part-b></app-content-part-b>
上面这段代码会带入到content-part-a
里面对应的select
选择名所在的ng-content
位置