Angular-3种创建动态内容的方式

栏目: JavaScript · 发布时间: 5年前

内容简介:写在最前,本文提到的“模板”都是ng-template;假设的模态组件也只是实现模态内容;为了缩减文章的篇幅,只保留了重要的部分。完整的例子在线上。在开发过程中,难免会遇到公共组件需要Input模板或input组件的时候,以增加公共组件交互或展示的灵活性。题外话:input组件的方式,可以扩展为依靠服务在业务模块中进行配置,以达到每个模块所用的同一个公共组件拥有不同的交互。下一篇文章将会谈谈。

写在最前,本文提到的“模板”都是ng-template;假设的模态组件也只是实现模态内容;为了缩减文章的篇幅,只保留了重要的部分。完整的例子在线上。

在开发过程中,难免会遇到公共组件需要Input模板或input组件的时候,以增加公共组件交互或展示的灵活性。

题外话:input组件的方式,可以扩展为依靠服务在业务模块中进行配置,以达到每个模块所用的同一个公共组件拥有不同的交互。下一篇文章将会谈谈。

1. 使用 ngTemplateOutlet 和 ngComponentOutlet

ngTemplateOutlet: 根据一个提前备好的 TemplateRef 插入一个内嵌视图。ngComponentOutlet: Instantiates a single Component type and inserts its Host View into current View. NgComponentOutlet provides a declarative approach for dynamic component creation.

假设要写一个表格组件,名为wtable,需要自定义单元格内容,组件ts有如下内容。

线上代码

  • 使用场景

<wtable [columns]="['姓名','年龄']" [rows]="[{name: 'ww', age: 11}, {name:'yy', age: 22}]" [cellContent]="custom"></wtable>

 <ng-template #custom let-data let-column="column" let-row="row" let-index="index">
    <!-- 在这里就可以获取数据搞事情啦 -->
    {{column}}: {{data}}<br>
    {{index}} 行<br>
    行数据: {{row | json}}
 </ng-template>复制代码
  • wtable组件的html

<tbody>
  <tr *ngFor="let row of rows;index as i;">
    <td *ngFor="let cell of row | keyvalue">
      <!-- 模板 -->
      <ng-container *ngIf="tpl">
        <ng-container *ngTemplateOutlet="tpl; context:outCellContext(cell.key, cell.value, row, i);"></ng-container>
      </ng-container>
      <!-- 组件不太好用 -->
      <ng-container *ngIf="comp">
        <ng-container *ngComponentOutlet="comp"></ng-container>
      </ng-container>
    <td>
  </tr>
</tbody>复制代码
  • wtable组件ts

// 此处为内部变量传递给外部模板使用,所需的数据
  outCellContext(cellKey, cellValue, row, index) {
    return {
      $implicit: cellValue, // 默认传出cellValue数据
      column: cellKey, // 指定字段
      row: row, // 行数据
      index: index // 行索引
    }
  }
}复制代码

2. 使用ViewContainerRef

表示可以将一个或多个视图附着到组件中的容器。

假设要写一个模态框组件wmodal,需要将模板或组件在模态框里展示。但是又不想html里用*ngIf来判断内容的显示,两个三个还可以接受,那要是7、8个或以上呢?让我们看看下面这个例子。

线上代码

  • 使用场景

<!-- 组件 -->
<wmodal [content]="comp" [compParams]="{data: '我是调用wmodal传入的值'}" (compOut)="wmodalOut($event)"></wmodal>

<!-- 模板 -->
<wmodal [content]="modalTpl"></wmodal>
<ng-template #modalTpl let-data let-other="other">
  data: {{data | json}} <br>
  other: {{other}}
</ng-template>复制代码
  • 在wmodal内需要做点什么呢?首先是html

// 占个位,这里我要放传入的模板或组件了
  <ng-template #container></ng-template>

复制代码
  • 接着是wmodal的ts

ngAfterContentInit() {
  // 依然是判断content类型
  if (this.content instanceof Type) {
    const comp = this.container.createComponent(this._compFac.resolveComponentFactory(this.content));
    // 将组件所需参数合并到组件实例中
    if (this.compParams) {
      Object.assign(comp.instance, this.compParams);
    }
    // 订阅组件
    for (const prop in comp.instance) {
      if (comp.instance.hasOwnProperty(prop)) {
        const subject = comp.instance[prop];
        // 筛选组件output事件
        if (subject instanceof EventEmitter) {
          this._compSubs.push(
            // 订阅组件output事件
            subject.subscribe(data => {
              this.compOut.emit(data);
            })
          );
        }
      }
    }
  } else {
    // 创建模板就比较简单了
    // 留意一下第二个参数,若是需要将组建的某些数据传出则可以这样
    const _data = {a: 1, b: 2};
    this.container.createEmbeddedView(this.content, {$implicit: _data, other: 2});
  }
}复制代码

3. 使用ApplicationRef

A reference to an Angular application running on a page.

假设还是modal组件

  • 使用场景

<wmodal2 [content]="comp" [compParams]="{data: '我是调用wmodal2传入的值'}" (compOut)="wmodalOut($event)"></wmodal2>复制代码
  • 惯例,wmodal2 html

<!-- 什么都没有 -->

复制代码
  • wmodal2 ts

ngAfterContentInit() {
  const comp = this._compFaRes.resolveComponentFactory(this.content).create(this._injector);
  this._e.nativeElement.appendChild(comp.location.nativeElement);

  // 此处与第2点一样,订阅output和给input赋值

  // 去掉timeout你就知道为什么了
  // 具体原因可以看我专栏的的第一篇文章
  const timeId = setTimeout(() => {
    this._appref.attachView(comp.hostView);
    clearTimeout(timeId);
  }, 100)
}复制代码

结束语

本文并未对3种方式进行对比,只是个人对于3种方式的使用理解。 简单的总结一下:

  • 使用1,会让html代码比较多,不易维护;而且1是通过2来实现得, 传送门

  • 1、2都需要插座代码(可见的outlet),对于模板的创建都需要context来传递变量,3不需要插座代码;

  • 2是比较常见的使用方式

  • 使用3的方式来仅可以创建组件且还有更大的用处

  • 创建组件都需要手动为input赋值并订阅output

有兴趣的还可以看看angular源码,其中 ngForngIf 皆是由第2种方式来实现得。

参考资料:


以上所述就是小编给大家介绍的《Angular-3种创建动态内容的方式》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

CASIO fx-5800P编程计算器公路与铁路施工测量程序

CASIO fx-5800P编程计算器公路与铁路施工测量程序

2011-8 / 40.00元

《CASIO fx-5800P 编程计算器公路与铁路施工测量程序(第2版)》内容简介:第2版是一本全新的图书。书中的QH2-7T与QH2-8T程序都具有三维中边桩坐标正、反算,路基超高及边桩设计高程计算,边坡坡口与坡脚计算,桥墩桩基坐标计算,隧道超欠挖计算等功能。QH2-7T为交点法程序,QH2-8T为线元法程序,两个程序均使用数据库子程序输入平竖曲线的全部设计数据。测试程序各项功能所用的案例均取......一起来看看 《CASIO fx-5800P编程计算器公路与铁路施工测量程序》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换