Cette fois, je vais vous apporter une explication détaillée des étapes à suivre pour qu'Angular utilise la méthode du composant de chargement dynamique pour implémenter Dialog. Quelles sont les précautions pour qu'Angular utilise la méthode du composant de chargement dynamique pour implémenter Dialog. . Ce qui suit est un cas pratique, jetons un coup d'œil.
Les articles et tutoriels en ligne se terminent essentiellement lorsque le composant est chargé ! Disparu? ! Et il ne peut y avoir qu'une seule boîte de dialogue. Si vous souhaitez ouvrir une autre boîte de dialogue, vous devez d'abord détruire la boîte de dialogue actuellement ouverte. Après avoir vu l'implémentation du matériel, je me reproche d'être trop stupide pour comprendre le code source, je ne peux donc que l'implémenter. à ma manière. Le composant dialog est
Le but du composant Dialog : plusieurs Dialogs peuvent exister en même temps, et le Dialog spécifié peut être détruit. Après destruction, aucun composant ne reste dans le HTML et. des rappels sont fournis
Il existe deux façons de charger dynamiquement des composants Avant la version angulaire 4.0, ComponentFactoryResolver était utilisé pour l'implémenter. Après angulaire 4.0, le ngComponentOutlet plus pratique peut être utilisé pour l'implémenter
. Le chargement dynamique est réalisé via ComponentFactoryResolver
Tout d'abord, trions la relation entre ViewChild, ViewChildren, ElementRef, ViewContainerRef, ViewRef, ComponentRef et ComponentFactoryResolver :
ViewChild et ViewChildren
ViewChild est référencé via des modèles La variable (#) ou la directive (directive) est utilisée pour obtenir Angular Dom classe abstraite . ViewChild peut être encapsulé en utilisant ElementRef ou ViewContainerRef.
@ViewChild('customerRef') customerRef:ElementRef;
ViewChildren est utilisé pour obtenir QueryList via des variables ou des instructions de référence de modèle, comme un tableau composé de plusieurs ViewChilds.
@ViewChildren(ChildDirective) viewChildren: QueryList<ChildDirective>;
ElementRef et ViewContainerRef
ViewChild peuvent être encapsulés à l'aide d'ElementRef ou ViewContainerRef Alors, quelle est la différence entre ElementRef et ViewContainerRef ?
Encapsulez-le avec ElementRef, puis obtenez l'élément Dom natif via .nativeElement
console.log(this.customerRef.nativeElement.outerHTML);
ViewContainerRef : le conteneur de la vue, y compris la méthode de création de la vue et l'API pour son fonctionnement la vue (commune aux composants et aux modèles) définie). L'API renverra ComponentRef et ViewRef, alors quels sont ces deux-là ?
// 使用ViewContainetRef时,请使用read声明 @ViewChild('customerRef',{read: ViewContainerRef}) customerRef:ViewContainerRef; ··· this.customerRef.createComponent(componentFactory) // componentFactory之后会提到
ViewRef et ComponentRef
ViewRef est la plus petite unité d'interface utilisateur. Ce que l'API ViewContainerRef exploite et obtient est ViewRef
ComponentRef : vue hôte. (Vue de l'instance du composant) Grâce à la référence à la vue du composant créée par ViewContainerRef, vous pouvez obtenir les informations sur le composant et appeler la méthode du composant
ComponentFactoryResolver
Pour obtenir le ComponentRef , vous devez appeler ViewContainer. La méthode createComponent doit transmettre les paramètres créés par ComponentFactoryResolver
constructor( private componentFactoryResolver:ComponentFactoryResolver ) { } viewInit(){ componentFactory = this.componentFactoryResolver.resolveComponentFactory(DialogComponent); // 获取对组件视图的引用,到这一步就已经完成了组件的动态加载 componentRef = this.customerRef.createComponent(componentFactory); // 调用载入的组件的方法 componentRef.instance.dialogInit(component); }
L'implémentation spécifique
let composantFactory ,componentRef;
@ViewChild('customerRef',{read: ViewContainerRef}) customerRef:ViewContainerRef; constructor( private componentFactoryResolver:ComponentFactoryResolver ) { } viewInit(){ // DialogComponent:你想要动态载入的组件,customerRef:动态组件存放的容器 componentFactory = this.componentFactoryResolver.resolveComponentFactory(DialogComponent); componentRef = this.customerRef.createComponent(componentFactory); }
Réaliser un chargement dynamique via ngComponentOutlet
ngComponentOutlet réduit considérablement la quantité de code, mais il n'est pris en charge que par les versions après 4.0
Implémentation spécifique
Créer un nœud de stockage de composants dynamiques dans dialog.component.html
<ng-container *ngComponentOutlet="componentName"></ng-container>
Passez le composant (pas le nom du composant) et tout ira bien. Pourquoi cela peut être aussi simple !
dialogInit(component){ this.componentName = component; };
Implémentation de dialogue
L'idée d'implémentation est la suivante : créez d'abord un composant de dialogue pour héberger d'autres composants, par exemple la boîte de dialogue Créez des masques et des animations et créez un service pour contrôler la génération et la destruction de la boîte de dialogue. Cependant, le service génère uniquement la boîte de dialogue. Les composants de la boîte de dialogue doivent encore être générés dans le composant de boîte de dialogue
. 1. Écrivez d'abord un service public. Utilisé pour obtenir le viewContainerRef du composant racine (j'ai essayé ApplicationRef pour obtenir le viewContainerRef du composant racine mais j'ai échoué, je l'ai donc écrit en tant que service)
gerRootNode(...rootNodeViewContainerRef){ if(rootNode){ return rootNode; }else { rootNode = rootNodeViewContainerRef[0]; }; } // 然后再根组件.ts内调用 this.fn.gerRootNode(this.viewcontainerRef);
2. Créez dialog.service.ts et définissez trois méthodes : open et close. , utilisez ViewContainerRef pour créer le composant de dialogue. Avant la création, vous devez appeler ComponentFactoryReslover et transmettre le DialogComponent dans la boîte de dialogue
let componentFactory; let componentRef; @Injectable() export class DialogService { constructor( private componentFactoryResolver:ComponentFactoryResolver private fn:FnService ) { } open(component){ componentFactory = this.componentFactoryResolver.resolveComponentFactory(DialogComponent); // 这里的获取的是ComponentRef containerRef = this.fn.gerRootNode().createComponent(componentFactory); // 将containerRef存储下来,以便之后的销毁 containerRefArray.push(containerRef); // 调用了组件内的初始化方法,后面会提到 return containerRef.instance.dialogInit(component,containerRef); } // 这里有两种情况,一种是在当前组件和dialog组件关闭调用的,因为有返回值所以可以关闭指定的dialog;还有一种是在插入到dialog组件内的组件调用的,因为不知道父组件的信息,所以默认关闭最后一个dialog close(_containerRef=null){ if( _containerRef ){ return _containerRef.containerRef.instance.dialogDestory(); }else{ containerRefArray.splice(-1,1)[0].instance.dialogDestory(); } } }
3. composant.ts. Utilisez ngComponentOutlet pour l'implémenter ici (ngComponentOutlet est mentionné ci-dessous, juste pour être paresseux. , utilisé directement)
let containerRef,dialogRef = new DialogRef(); export class DialogComponent implements OnInit { componentName; constructor( private fn:FnService ) { } dialogInit( _component, _containerRef){ this.componentName = _component; containerRef = _containerRef; dialogRef['containerRef'] = containerRef; return dialogRef; }; dialogDestory(){ let rootNode = this.fn.gerRootNode(); // 等待动画结束再移除 setTimeout(()=>{ // 这里用到了 viewContainerRef 里的indexOf 和 remove 方法 rootNode.remove(rootNode.indexOf(containerRef.hostView)); },400); dialogRef.close(); return true; }; }
4、这里还创建了一个 DialogRef 的类,用来处理 dialog 关闭后的回调,这样就可以使用 XX.afterClose().subscribe() 来创建回调的方法了
@Injectable() export class DialogRef{ public afterClose$ = new Subject(); constructor(){} close(){ this.afterClose$.next(); this.afterClose$.complete(); } afterClose(){ return this.afterClose$.asObservable(); } }
创建和销毁dialog
// 创建 let _viewRef = this.dialogService.open(DialogTestComponent); _viewRef.afterClose().subscribe(()=>{ console.log('hi'); }); // 销毁 this.dialogService.close()
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!