angular 学习笔记 ( Dynamic Component 动态组件)

动态组件分 2 种 

1. Jit

2. Aot

Jit 的情况下你可以动态的写组件模板, 最后 append 出去, 类似 ng1 的 $compile 

Aot 的话, 模板是固定的, 我们只是可以动态创建 component 然后 append 出去

这一篇只会谈及 Aot 

 

要知道的事项 : 

1. 所有要动态的组件除了需要 declarations之外还要声明到 entryComponents 里头, 原因是 ng 是通过扫描模板来 import component class 的, 动态组件不会出现在模板上所以我们要用另一个 way 告诉 ng。

            providers: [
                {provide: ANALYZE_FOR_ENTRY_COMPONENTS, useValue: [AComponentClass, BComponentClass], multi: true}
            ]

要方便扩展的话可以用 provides, ng-router 也是用这个实现的.

2. 目前只有动态组件,没有动态指令 (呃..所以动态创建的组件就不能附带指令咯.../.\)

3. 例子 

复制代码
@Component({
    selector: 'aaa',
    template: ``
})
export class AAAComponent implements OnInit, AfterContentInit {
    constructor(
        private vcr: ViewContainerRef,
        private cfr: ComponentFactoryResolver
    ) { }

    @ContentChildren("dynamic", { read: ElementRef }) elem: QueryList<ElementRef>  //read 的作用是强转类型

    ngOnInit() {


    }

    ngAfterContentInit() {                   
        let providers = ReflectiveInjector.resolve([AbcService]); //为组件添加 providers
        let injector = ReflectiveInjector.fromResolvedProviders(providers, this.vcr.parentInjector); //创建注入器给 component (记得要继承哦)
        let factory = this.cfr.resolveComponentFactory(AbcComponent); //创建 component 工厂
        let component = factory.create(injector,[[this.elem.first.nativeElement],[this.elem.last.nativeElement] ]); //创建 component, 这是就把注入器放进了, 后面的 array 是给 ng-content 用的
        component.instance.name = "keatkeat"; // 对 input, output 做点东西 
        this.vcr.insert(component.hostView, 0); // 插入到模板中  0 是 position, 如果是 0 其实可以不用放. 

        // 如果不需要设定 providers 的话,可以省略一些 : 
        // let factory = this.resolver.resolveComponentFactory(AbcComponent);  
        // let component = this.vcr.createComponent(factory, 0);
        // component.instance.name = "keatkeat";   
    }
}
复制代码

里头说的 ng-content, 就是 Projectable nodes , 我个人认为这个做法还不太理想,因为 ng-content 应该是可以通过 select 找到对应的 tranclude 的,不过这里的参数 array 已经固定了 tranclude 的位置. 

所以目前, 如果你要做类似 tranclude 的事情, 改用 input 传递 templateRef 反而会比较容易控制. 

类似这样 

复制代码
@Component({    
    template : `
        <p>final</p>
        <template [ngTemplateOutlet]="template" [ngOutletContext]="{ innerValue : 'huhu' }" ></template>
    `,
    selector : "final"
})
export class FinalComponent implements OnInit {
    constructor(
    ) { }

    @Input()
    template : TemplateRef<any> //传进来

    ngOnInit() {       
        console.log(this.template);
    }
}
复制代码

 4. 个人的想法 

一个动态组件应该和平时的组件必须是一样的,意思是我们可以随时把任何一个组件改成动态调用的方式. 

不过目前 ng 支持的不是很好

-input, output (支持)

-tranclude (Projectable nodes 显然和 ng-content配合不上)

-在 component 上放指令 (动态创建的 component, 没办法加上指令, 这导致了 dynamic accessor 很难写)

例子 

复制代码
@Component({
    templateUrl : "./debugTwo.component.html"
})
export class DebugTwoComponent implements OnInit, AfterViewInit {

    constructor(
        private fb : FormBuilder,
        private cfr : ComponentFactoryResolver
    ) { }

    form : FormGroup
    @ViewChild("target", { read : ViewContainerRef }) target : ViewContainerRef
    ngOnInit() { 

        this.form = this.fb.group({
            age : [0]
        });
    }

    ngAfterViewInit()
    {
        let factory = this.cfr.resolveComponentFactory(AccessorComponent);  
        let component = this.target.createComponent(factory, 0);
        let ctrl = this.form.controls["age"];
        component.instance.writeValue(ctrl.value); //需要手动去调用 writeValue, registerOnChange, registerOnTouched, 如果可以直接加上 formControlName 指令,就方便多了.
        component.instance.registerOnChange((v) => {
            ctrl.setValue(v);
        });
        //component.instance.template = this.template;
    }
}
复制代码

 

5. 一些常用到的类 

-ViewContainerRef : 好比一个 root div, 通常我们引用它目的就是 append element 进去.

 常用 : createEmbeddedView, createComponent, insert

-TemplateRef : 指的是 <template> 里面的内容.  

 常用 : createEmbeddedView

-ElementRef : dom 

 常用 : nativeElement (获取 dom 对象引用)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值