设为首页 加入收藏

TOP

动态创建angular组件实现popup弹窗(一)
2017-10-10 12:39:43 】 浏览:6831
Tags:动态 创建 angular 组件 实现 popup 弹窗

承接上文,本文将从一个基本的angular启动项目开始搭建一个具有基本功能、较通用、低耦合、可扩展的popup弹窗(脸红),主要分为以下几步:

  1. 基本项目结构搭建
  2. 弹窗服务
  3. 弹窗的引用对象
  4. 准备作为模板的弹窗组件
  5. 使用方法

基本项目结构

因为打算将我们的popup弹窗设计为在npm托管的包,以便其他项目可以下载并使用,所以我们的启动项目大概包含如下结构:

  • package.json // 定义包的基本信息,包括名字、版本号、依赖等
  • tsconfig.json // angular项目基于typescript进行搭建,需要此文件来指定ts的编译规则
  • ... // tslint等一些帮助开发的配置文件
  • index.ts // 放在根目录,导出需要导出的模块、服务等
  • /src // 实际模块的实现
  • /src/module.ts // 模块的定义
  • /src/service.ts // 弹窗服务
  • /src/templates/* // 作为模板的组件
  • /src/popup.ref.ts // 对创建好的组件引用的封装对象
  • /src/animations.ts // 动画的配置

现在我们只来关心src目录下的实现。

弹窗服务

弹窗服务的职责是提供一个叫做open的方法,用来创建出组件并显示,还得对创建好的组件进行良好的控制:

import { Injectable, ApplicationRef, ComponentFactoryResolver,
    ComponentRef, EmbeddedViewRef } from '@angular/core';
import { YupRef, ComponentType } from './popup.ref';

@Injectable()
export class DialogService {
    private loadRef: YupRef<LoadComponent>;
    constructor(
        private appRef: ApplicationRef,
        private compFactRes: ComponentFactoryResolver
    ) {}
    // 创建一个组件,组件通过泛型传入以做到通用
    public open<T>(component: ComponentType<T>, config: any) {
        // 创建组件工厂
        const factory = this.compFactRes.resolveComponentFactory(component);
        // 创建一个新的弹窗引用
        const dialogRef = new YupRef(factory, config);
        // 将创建好的组件引用(由弹窗引用创建并返回)append到body标签下
        window.document.body.appendChild(this.getComponentRootNode(dialogRef.componentRef()));
        // 加入angular脏检查
        this.appRef.attachView(dialogRef.componentRef().hostView);
        // 将创建的弹窗引用返回给外界
        return dialogRef;
    }
    // 参考自Material2,将ComponentRef类型的组件引用转换为DOM节点
    private getComponentRootNode(componentRef: ComponentRef<any>): HTMLElement {
        return (componentRef.hostView as EmbeddedViewRef<any>).rootNodes[0] as HTMLElement;
    }
}

// 参考自Material2 用于作为传入组件的类型
export interface ComponentType<T> {
    new (...args: any[]): T;
}

弹窗的引用对象

上面服务中的open方法实际上把创建组件的细节通过new一个YupRef即弹窗引用来实现,这是因为考虑到服务本身是单例,如果仅使用open方法直接创建多个弹窗,在使用时会丢失除了最后一个弹窗外的控制能力,笔者这里采用的办法是将创建的弹窗封装成一个类即YupRef:

import { ComponentRef, InjectionToken, ReflectiveInjector, ComponentFactory } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
// 用于注入自定义数据到创建的组件中
export const YUP_DATA = new InjectionToken<any>('YUPPopupData');

export class YupRef<T> {
    // 弹窗关闭的订阅
    private afterClose$: Subject<any>;
    // 弹窗引用变量
    private dialogRef: ComponentRef<T>;
    constructor(
        private factory: ComponentFactory<T>,
        private config: any // 传入的自定义数据
    ) {
        this.afterClose$ = new Subject<any>();
        this.dialogRef = this.factory.create(
            ReflectiveInjector.resolveAndCreate([
                {provide: YUP_DATA, useva lue: config}, // 注入自定义数据
                {provide: YupRef, useva lue: this} // 注入自身,这样就可以在创建的组件里控制组件的关闭等
            ])
        );
    }
    // 提供给外界的对窗口关闭的订阅
    public afterClose(): Observable<any> {
        return this.afterClose$.asObservable();
    }
    // 关闭方法,将销毁组件
    public close(data?: any) {
        this.afterClose$.next(data);
        this.afterClose$.complete();
        this.dialogRef.destroy();
    }
    // 提供给弹窗服务以帮助添加到DOM中
    public componentRef() {
        return this.dialogRef;
    }
}

这样一来每次调用open方法后都能得到一个YupRef对象,提供了关闭方法以及对关闭事件的订阅方法。

预制弹窗组件

弹窗服务中的open方法需要两个参数,第二个是传入的自定义数据,第一个就是需要创建的组件了,现在我们创建出几个预制组件,以dialog.component为例:

import { Component, Injector } from '@angular/core';
import { YupRef, YUP_DATA } from '../popup.ref';
import { mas
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇webpack 处理CSS 下一篇es6的解构赋值

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目