app-xxx
)ts
动态插入到dom
中到组件,可以视为动态组件alert
组件来解释创建动态组件的步骤,最后效果如下:创建静态组件
ng g c components/alert2 -s -c OnPush
-c OnPush
就是更改angular
变更检测策略,--changeDetection=Default|OnPush
的简写,会自动在组件里添加OnPush模式:// alert.component.ts ... @Component({ selector: 'app-alert', // ... changeDetection: ChangeDetectionStrategy.OnPush })
先搭好组件的结构
<!-- alert.component.html --> <div class="alert alert-primary" role="alert"> <span class="content">这是一段提示文字</span> <i class="close">×</i> </div>
// alert.component.ts ... @Component({ selector: 'app-alert', templateUrl: './alert.component.html', styles: [` .close {display: block; width: 20px; height: 20px; position: absolute; right: 10px; top: 50%; margin-top: -15px; cursor: pointer;} `], changeDetection: ChangeDetectionStrategy.OnPush })
需求分析
- 通过页面逻辑动态生成组件,这里就通过点击事件;
- 可以动态加载内容及修改组件主题;
- 关闭按钮销毁组件。
将alert组件所需参数动态化
<!-- alert.component.html --> <div [class]="wrapClass" role="alert"> <span class="content">{{options.content}}</span> <i class="close" (click)="closed.emit();">×</i> </div>
// alert.component.ts ... // 定义主题参数 type AlertTheme = 'primary' | 'danger' | 'warning' | 'secondary' | 'success' | 'info' | 'dark' | 'light'; // 限定参数 export interface AlertOption { content: string; theme?: AlertTheme; } ... export class AlertComponent implements OnInit { // Required将对象类型AlertOption的所有可选属性转化为必填属性 options: Required<AlertOption> = { content: '', theme: 'primary', } // 注册关闭的输出事件 @Output() readonly closed = new EventEmitter(); constructor() { } ngOnInit(): void {} // 获取class get wrapClass(): string { return `alert alert-${this.options.theme}` } // 合并默认参数与传入的参数 setOptions(options: AlertOption): void { this.options = {...this.options, ...options} } }
<!-- alert.component.html --> <div [class]="wrapClass" role="alert"> <span class="content">{{options.content}}</span> <i class="close" (click)="closed.emit();">×</i> </div>
父组件中实现动态调用逻辑
现在,我们不使用<app-alert>
的方式调用,使用按钮动态创建:
<!-- alert-box.component.html(父组件) --> <div class="alert-comp"> <!-- <app-alert></app-alert> --> <button class="btn btn-primary btn-small" (click)="showAlert()">生成alert组件</button> </div>
实现逻辑
// alert-box.component.ts(父组件) import {Component, OnInit, ChangeDetectionStrategy, ComponentFactoryResolver, Injector, ComponentRef, ApplicationRef, EmbeddedViewRef} from '@angular/core'; import { AlertComponent } from '../alert/alert.component'; ... export class AlertBoxComponent implements OnInit { private component: AlertComponent; private componentRef: ComponentRef<AlertComponent>; constructor( private cfr: ComponentFactoryResolver, private inject: Injector, private appRef: ApplicationRef ) { } ngOnInit(): void {} // 实现按钮点击逻辑 showAlert() { // 判断是否已经创建组件 if(!this.component) { this.component = this.createContainer(); } // 传递所需参数 this.component.setOptions({content: '这是动态创建组件传入的内容', theme: 'success'}) } // 创建 private createContainer(): AlertComponent { /** * 1.创建组件工厂: * constructor中注入ComponentFactoryResolver这个类 * 创建指定类型的组件工厂(生产指定类型的组件) * */ const factory = this.cfr.resolveComponentFactory<AlertComponent>(AlertComponent); /** * 2.工厂创建ComponentRef * constructor中注入Injector这个类 * 根据指定的类型,创建组件的实例 */ this.componentRef = factory.create(this.inject); /** * constructor中注入ApplicationRef这个类 * 3.将组件试图添加到视图树中,以激活变更检测 * */ this.appRef.attachView(this.componentRef.hostView); // 4.将组件到模版(包括app-alert标签),添加到body最后(当然,可以添加到任何位置) document.body.appendChild((this.componentRef.hostView as EmbeddedViewRef<{}>).rootNodes[0] as HTMLElement); // 5.监听组件销毁事件 this.componentRef.onDestroy(() => { console.log('component destory'); }); // 获取组件实例,相当于用@ViewChild获取子组件一样 const { instance } = this.componentRef; // 6.监听组件的output事件 // subscribe是rxjs的内容,以后会介绍 instance.closed.subscribe(() => { this.componentRef.destroy(); this.component = null; }); return instance; } }
本文转载自:公众号 岩弈 Angular教程,版权归原作者所有,本博客仅以学习目的的传播渠道,不作版权和内容观点阐述,转载时根据场景需要有所改动。
最新评论