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

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

内容简介:写在最前,本文提到的“模板”都是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种创建动态内容的方式》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

RESTful Web Services Cookbook

RESTful Web Services Cookbook

Subbu Allamaraju / Yahoo Press / 2010-3-11 / USD 39.99

While the REST design philosophy has captured the imagination of web and enterprise developers alike, using this approach to develop real web services is no picnic. This cookbook includes more than 10......一起来看看 《RESTful Web Services Cookbook》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

随机密码生成器
随机密码生成器

多种字符组合密码

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具