惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

C
Check Point Blog
有赞技术团队
有赞技术团队
博客园 - 三生石上(FineUI控件)
博客园_首页
博客园 - 【当耐特】
WordPress大学
WordPress大学
月光博客
月光博客
博客园 - 叶小钗
S
SegmentFault 最新的问题
雷峰网
雷峰网
H
Help Net Security
宝玉的分享
宝玉的分享
A
About on SuperTechFans
IT之家
IT之家
J
Java Code Geeks
Hugging Face - Blog
Hugging Face - Blog
D
DataBreaches.Net
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - 聂微东
T
The Blog of Author Tim Ferriss
B
Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Y
Y Combinator Blog

zodream梦想开源/个人编程日记

文件解析笔记-zodream梦想开源/个人编程日记 密码本开发笔记之读写与保存-zodream梦想开源/个人编程日记 SkiaSharp 把 pixel byte[] 转成 SKBitmap-zodream梦想开源/个人编程日记 nas 使用 Docker 安装 gogs-zodream梦想开源/个人编程日记 复制 android 手机中的文件到电脑-zodream梦想开源/个人编程日记 周报:寻找优质的周刊-zodream梦想开源/个人编程日记 开发日志:对Markdown的代码块新增引用来源支持-zodream梦想开源/个人编程日记 周报:怎么写技术类的教程文章-zodream梦想开源/个人编程日记 css display:flex 布局尺寸超出问题-zodream梦想开源/个人编程日记 周报:SEO优化的思考-zodream梦想开源/个人编程日记 Edge 浏览器不适用 Edge Image Viewer 打开图片 -zodream梦想开源/个人编程日记 SEO 学习笔记(一) 内容来源-zodream梦想开源/个人编程日记 PHP 实现双因素身份认证(2FA)-zodream梦想开源/个人编程日记 WPF MVVM 获取List 多选数据-zodream梦想开源/个人编程日记 Burp Suite 抓包-zodream梦想开源/个人编程日记 使用 indexnow 注意事项-zodream梦想开源/个人编程日记 Godot 使用字体图标 例如: Iconfont、FontAwesome-zodream梦想开源/个人编程日记 angular 15 对指定页面进行访问限制-zodream梦想开源/个人编程日记 CSS 使用 column-count 实现瀑布流出现内容分割的解决办法-zodream梦想开源/个人编程日记 input 确认按键事件在手机端不生效-zodream梦想开源/个人编程日记 C# 使用socket 进行通讯-zodream梦想开源/个人编程日记 Maui开发中Windows应用开启管理员权限-zodream梦想开源/个人编程日记 Maui 中自定义控件-zodream梦想开源/个人编程日记 angular 14 使用 ng-template 实现tree 结构显示-zodream梦想开源/个人编程日记 c# 动态安装和卸载dll-zodream梦想开源/个人编程日记 慎用 CompositionTarget.Rendering-zodream梦想开源/个人编程日记 c# 重写 c++ 程序笔记:数据初始化-zodream梦想开源/个人编程日记 源码编译 aseprite-zodream梦想开源/个人编程日记 记录一下字符串分隔split各语言之间的不同-zodream梦想开源/个人编程日记 c# Gzip解码无头内容-zodream梦想开源/个人编程日记
angular 16 动态生成组件-zodream梦想开源/个人编程日记
zodream · 2021-07-02 · via zodream梦想开源/个人编程日记

angular 16 动态生成组件

需求

在页面中生成一个确认弹窗

新的实现方式

第一步,获取需要的工具

@Injectable({
    providedIn: 'root'
})
export class DialogService {

    public containerRef: ViewContainerRef; //需要从Component中获取,然后传递进来
    constructor(
        private injector: Injector,
    ) { }
}

12345678910

ViewContainerRef 的获取方式

  1. 第一种在 Component 初始化时获取

    @Component({
     selector: 'app-dialog-container',
     template: '',
     styles: [''],
    })
    export class DialogContainerComponent {
    
     constructor(
         private service: DialogService,
         private viewContainerRef: ViewContainerRef,
     ) {
         this.service.containerRef = this.viewContainerRef;
     }
    }

    1234567891011121314

  2. template 中通过 ng-container 获取

    @Component({
     selector: 'app-dialog-container',
     template: '<ng-container #modalVC></ng-container>',
     styles: [''],
    })
    export class DialogContainerComponent implements AfterViewInit {
    
     @ViewChild('modalVC', {read: ViewContainerRef})
     private viewContainerRef: ViewContainerRef;
    
     constructor(
         private service: DialogService,
     ) {
    
     }
    
     ngAfterViewInit(): void {
         this.service.containerRef = this.viewContainerRef;
     }
    }

    1234567891011121314151617181920

主要区别:就是增加的元素节点为兄弟节点,所以,第一种添加的弹窗是在外面的,不受 app-dialog-container 中的样式影响;第二种是作为子元素添加的,受样式影响

第二步,实现动态生成组件

component 为组件的类名

const dialogRef = this.containerRef.createComponent(component, {
    injector: this.injector
});

// dialogRef.instance 就是组件的实例 

12345

第三步,移除组件

如果需要在组件初始化,自动注入值或传值,则需要自定义 injector

import { InjectFlags, Injector, ProviderToken } from '@angular/core';

// 这个类是传值的载体
export class DialogPackage<T = any> {
    constructor(
        public data: T,
        public dialogId: any,
    ) {
    }
}

// 这是自定义的注射器
export class DialogInjector<T> implements Injector {

    constructor(
        private data: DialogPackage,
        private parentInjector: Injector
      ) {}

    get<T>(token: ProviderToken<T>, notFoundValue?: T, option?: InjectOptions): T;
    get(token: any, notFoundValue?: any);
    get(token: any, notFoundValue?: any, flags?: any): any {
        if (token === DialogPackage) {
            return this.data;
          }
          return this.parentInjector.get<T>(token, notFoundValue, flags);
    }

}

1234567891011121314151617181920212223242526272829

第二步需要修改

const dialogInjector = new DialogInjector(new DialogPackage(option, dialogId), this.injector);
const dialogRef = this.containerRef.createComponent(component, {
    injector: dialogInjector
});

// dialogRef.instance 就是组件的实例 

123456

在组件中接收值

export class DialogConfirmComponent {

    constructor(
        private data: DialogPackage<DialogConfirmOption>,
        private service: DialogService,
    ) {

    }
}

123456789

过时实现代码

第一步,获取需要的工具

export class DialogService {

    constructor(
        private resolver: ComponentFactoryResolver,
        private applicationRef: ApplicationRef,
        private injector: Injector, 
        @Inject(DOCUMENT) private document: Document,
    ) { }


}

1234567891011

第二步,实现动态生成组件

component 为组件的类名

const dialogFactory = this.resolver.resolveComponentFactory(component);
const dialogRef = dialogFactory.create(this.injector);
// 正式添加到程序和添加到页面上,才能显示
this.applicationRef.attachView(dialogRef.hostView);
this.document.body.appendChild(dialogRef.location.nativeElement);

// dialogRef.instance 就是组件的实例 

1234567

第三步,移除组件

this.applicationRef.detachView(dialogRef.hostView);
this.document.body.removeChild(dialogRef.location.nativeElement);

12

如果需要在组件初始化,自动注入值或传值,则需要自定义 injector

import { InjectFlags, Injector, ProviderToken } from '@angular/core';

// 这个类是传值的载体
export class DialogPackage<T = any> {
    constructor(
        public data: T,
        public dialogId: any,
    ) {
    }
}

// 这是自定义的注射器
export class DialogInjector<T> implements Injector {

    constructor(
        private data: DialogPackage,
        private parentInjector: Injector
      ) {}

    get<T>(token: ProviderToken<T>, notFoundValue?: T, flags?: InjectFlags): T;
    get(token: any, notFoundValue?: any);
    get(token: any, notFoundValue?: any, flags?: any): any {
        if (token === DialogPackage) {
            return this.data;
          }
          return this.parentInjector.get<T>(token, notFoundValue, flags);
    }

}

1234567891011121314151617181920212223242526272829

第二步需要修改

const dialogFactory = this.resolver.resolveComponentFactory(component);
// 这里的option 可以是任何值
const dialogInjector = new DialogInjector(new DialogPackage(option, dialogId), this.injector);
const dialogRef = dialogFactory.create(dialogInjector);
// 正式添加到程序和添加到页面上,才能显示
this.applicationRef.attachView(dialogRef.hostView);
this.document.body.appendChild(dialogRef.location.nativeElement);

// dialogRef.instance 就是组件的实例 

123456789

在组件中接收值

export class DialogConfirmComponent {

    constructor(
        private data: DialogPackage<DialogConfirmOption>,
        private service: DialogService,
    ) {

    }
}

123456789

转载请保留原文链接: https://zodream.cn/blog/id/212.html