动态创建Angular组件实现popup弹窗功能

起步: 直接使用ngIf

把弹窗的DOM直接放在页面底下隐藏,通过ngIf这样的指令控制其显示。

改进: 封装成angular模块,通过服务控制其显示

直接使用ngIf的话,让人不爽的地方就在于不够通用,每个页面都得加DOM。改进的话可以把比较通用的一些DOM封装成组件,统一添加到全局页面中,并将显示的控制交给一个angular服务来控制其显示。

比如定义了两个组件(DialogComponent, AlertComponent),将他们都添加到AppComponent下,然后提供一个PopupService来控制组件的显示,并支持传递参数进去。

仅通过控制显示的方式仍不够通用且存在耦合

将弹窗组件封装然后使用服务来控制显示的方法看上去已经比较通用了,不过还存在两个尴尬的问题:

  1. 仍然需要在页面的某个地方放置一个弹窗组件,比如叫做PopupComponent,此组件负责渲染出默认隐藏的一些通用弹窗子组件,才能进行显示控制实现弹窗能力。
  2. 如果想要弹出一个自定义窗口的话就只能回到最上面另外写DOM放到需要弹出自定义弹窗的位置上,或者将自定义的标签通过innerHtml指令传入(富文本方式)。

由此可见这样的弹窗能力并没有做到非常通用,且必须手动放置弹窗插座(姑且这么叫)以致多了一处耦合。

动态创建弹窗

最理想的方式应该是: 在想要弹个窗口出来时直接一行代码把窗口弹出来,不用事先在哪里先把这个弹窗写好(或者说这一步不应该由弹窗控件的使用者来做,弹窗控件应该要自动完成这件事)。

而这一能力就涉及到angular的动态创建组件的能力了。

官网给出的用法

angular的官方文档中就有关于动态创建组件的用法。不过其使用的是ViewContainerRef服务,此服务提供了createComponent方法来在指定的视图容器下动态创建一个组件出来。

不过ViewContainerRef的尴尬点是只能在具体的指令、组件中使用,也就是说,必须告诉它打算在哪个地方创建新组建,这不还是需要实现创建好一个“弹窗插座”出来,才可以在这个“插座”中动态创建组件。

那有什么办法可以不给定视图容器而创建出组建来,通俗地讲问题就是: 不是在指令或者组件中创建组件,而是在服务中创建出组件,还要让这个组件显示到页面上去。

组建工厂——组件真正的创建者

在组件中创建组件的核心代码分两步:

创建组件工厂

let componentFactory = this.componentFactoryResolver.resolveComponentFactory(待创建组件);

把工厂提供给容器创建出组件

let componentRef = viewContainerRef.createComponent(componentFactory);

现在的问题在于,在服务中得不到viewContainerRef,工厂倒是能创建成功。

其实有工厂了已经足够了,查看componentFactory提供的成员里面包含了一个create方法,顾名思义这应该就是用来创建组件的了。

create方法有个必选参数类型为Injector,顾名思义就是注入器,即这个创建的组件打算注入些什么服务进去,暴力点直接写null也没问题。

直接使用工厂创建组件返回的同样是一个ComponentRef类型的引用,可见此时组件确实是创建出来了,但是还没有将其插入到视图中去。此时可以再暴力一点,直接用原生DOM操作插入到body标签的末尾去:

window.document.body.appendChild(
  this.getComponentRootNode(componentRef)
);
this.appRef.attachView(componentRef); // 注入ApplicationRef服务后使用
// ...
private getComponentRootNode(componentRef: ComponentRef<any>): HTMLElement {
  return (componentRef.hostView as EmbeddedViewRef<any>).rootNodes[0] as HTMLElement;
}
// ...

此办法是笔者从Material2的茫茫源代码中找到的,Google自己都直接这么插,那就放心使用了。这里不得不赞叹Material2中Dialog模块的实现,实在是有够复杂。

总结

本文主要在讲思路,扯到最后才开始要进入主题来动态创建组件,不过仅仅是创建出组件并添加到DOM中去还只是第一步,一个健壮的弹窗模块(Material2那样的)还得有一套完善的交互能力,比如弹出和关闭时的订阅和传值,这些就要通过注入服务到组件中来实现了,限于篇幅将在下一篇文章中回归实际实现一个通过动态创建组件实现的弹窗模块出来。

以上所述是小编给大家介绍的动态创建Angular组件实现popup弹窗功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • 详解Angular 4.x 动态创建组件

    动态创建组件 这篇文章我们将介绍在 Angular 中如何动态创建组件. 定义 AlertComponent 组件 首先,我们需要定义一个组件. exe-alert.component.ts import { Component, Input } from '@angular/core'; @Component({ selector: "exe-alert", template: ` <h1>Alert {{type}}</h1> `, }) export cl

  • Angular.js实现动态加载组件详解

    前言 有时候需要根据URL来渲染不同组件,我所指的是在同一个URL地址中根据参数的变化显示不同的组件:这是利用Angular动态加载组件完成的,同时也会设法让这部分动态组件也支持AOT. 动态加载组件 下面以一个Step组件为示例,完成一个3个步骤的示例展示,并且可以通过URL user?step=step-one 的变化显示第N个步骤的内容. 1.resolveComponentFactory 首先,还是需要先创建动态加载组件模块. import { Component, Input, Vie

  • angular 动态组件类型详解(四种组件类型)

    组件类型1:纯函数功能,而没有视图部分,即Factory(类似于$http) promise.component.html 常见的有内置的$http,$q之类的.一般使用promise与作用域进行交互 组件类型2:不是常驻于视图,而是动态插入的.有UI的一类组件,有输入交互.不常被调用(类似于Model对话框) factory.component.html 并发性.这里收到es6的启发.在factory内使用了构造函数,来区分不同的实例.当然,factory接口返回的类型要根据需求来定:仅仅是一

  • Angular 4根据组件名称动态创建出组件的方法教程

    一.理解angular组件 组件是一种特殊的指令,使用更简单的配置项来构建基于组件的应用程序架构,这样他能简单地写app,通过类似的web Component 或者angular2的样式.web Component 是一个规范.马上就要成为标准. 应用组件的优点: 比普通指令配置还简单 提供更好的默认设置和最好的实践 对基于组建的应用架构更优化. 对angular2的升级更平滑. 不用组建的情况: 对那些在 compile或者pre-link阶段要执行操作的指令,组件不能用,因为无法到达那个阶段

  • 动态创建Angular组件实现popup弹窗功能

    起步: 直接使用ngIf 把弹窗的DOM直接放在页面底下隐藏,通过ngIf这样的指令控制其显示. 改进: 封装成angular模块,通过服务控制其显示 直接使用ngIf的话,让人不爽的地方就在于不够通用,每个页面都得加DOM.改进的话可以把比较通用的一些DOM封装成组件,统一添加到全局页面中,并将显示的控制交给一个angular服务来控制其显示. 比如定义了两个组件(DialogComponent, AlertComponent),将他们都添加到AppComponent下,然后提供一个Popup

  • 详解vue 动态加载并注册组件且通过 render动态创建该组件

    基于 iview Tabs 组件实现 功能:为每个 tab 动态创建不同的.特定的组件内容,而不需要大量的 import 组件并进行 component 注册 Index.vue <template> <div class="content-left-menu"> <div class="item-contain layout-content"> <Tabs class="cmcc-ivu-tab2" t

  • Angular 4.x 动态创建表单实例

    本文将介绍如何动态创建表单组件,我们最终实现的效果如下: 在阅读本文之前,请确保你已经掌握 Angular 响应式表单和动态创建组件的相关知识,如果对相关知识还不了解,推荐先阅读一下 Angular 4.x Reactive Forms和 Angular 4.x 动态创建组件 这两篇文章.对于已掌握的读者,我们直接进入主题. 创建动态表单 创建 DynamicFormModule 在当前目录先创建 dynamic-form 目录,然后在该目录下创建 dynamic-form.module.ts

  • ASP.NET中根据XML动态创建使用WEB组件

    前段时间笔者在开发中需要动态创建WEB组件,本以为是小事一桩,谁知看时容易做时难.里面还真有些小问题.下面笔者就结合自己的程序来介绍一下如何动态创建并使用WEB组件,希望能给做类似工作的朋友提供一点帮助. 一.程序思路 程序主要分三部分: 1.程序要根据XML中的数据信息确定需要创建的WEB组件的个数. 2.动态创建WEB组件. 3.使用动态创建的WEB组件. 其中2和3是笔者要重点介绍的部分. 下面笔者就按照这三部分结合程序实例(以c#为例)来一一介绍. 二.读取XML文件 读取XML文件在很

  • vue 动态创建组件的两种方法

    Vue动态创建组件实例并挂载到body 方式一 import Vue from 'vue' /** * @param Component 组件实例的选项对象 * @param props 组件实例中的prop */ export function create(Component, props) { const comp = new (Vue.extend(Component))({ propsData: props }).$mount() document.body.appendChild(c

  • React创建对话框组件的方法实例

    原生的前端体系创建一个对话框可是再简单不过了.但是如果放到组件化思想下的react体系中,想要制作一个属于自己的对话框还是有一定的麻烦的.主要遇到的问题有两个:一是如何在子组件中创建body下的对话框组件,二是如何删除这个组件. 接下来我们就一步一步解决这两个问题. 我们先写好dialog组件:(所有的样式都不写了,这里实现一个原型) class Dialog extends Component{ constructor(props){ super(props); } render(){ ret

  • vue点击按钮动态创建与删除组件功能

    主要功能需求点: 点击左侧组件库按钮创建对应的不同的组件,并在右侧区域展示 点击右侧创建的组件中的删除按钮,删除对应的组件 删除对应的组件之后,下方的组件位置自动上移 效果图: 代码: 父组件代码(去除了css样式代码): <template> <div class="home"> <div class="container"> <div class="addZujian"> <div>

  • Angular懒加载动态创建显示该模块下声明的组件

    目录 环境: Angular 13.x.x 新建一个angular项目 懒加载工具栏组件 toolbar.module.ts toolbar.component.ts toolbar.component.html app.component.ts 环境: Angular 13.x.x angular中支持可以通过路由来懒加载某些页面模块已达到减少首屏尺寸, 提高首屏加载速度的目的. 但是这种通过路由的方式有时候是无法满足需求的. 比如, 点击一个按钮后显示一行工具栏, 这个工具栏组件我不希望它默

随机推荐