angular6的table組件開發的實現示例

這篇文章主要介紹了angular6的table組件開發的實現示例,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

背景及吐槽:

今年有機會再次接觸angualr這個框架,想起第一次接觸ng還是16年讀書的時候,當時還是ng1,然後學起來特別辛苦,學習曲線特別陡峭;而今年有一個項目重構直接採用了angular6,而後面該項目後面由我負責開發和維護,然後我又重新再學習了ng6,本以爲有ng1的基礎,學起來會好一些,然並卵,學習的曲線特別陡峭,但還是最後將ng6啃下來(很不情願去學的,但沒辦法)。迴歸到項目,該項目沒有引入其他組件庫,所以很多基礎組件都是自己開發(用ng開發那種酸爽很帶勁),其中table組件讓我思考了差不多兩個星期,最後才開發出來,吐槽完畢,接下來就介紹一下我的做法,我的做法不一定最正確。

形式:

主要參考element裏面的table組的格式:

vue:

<el-table :data="tableData">
  <el-table-column prop="date" label="日期"></el-table-column>
  <el-table-column label="操作">
   <template slot-scope="scope">
    <el-button @click="handleClick(scope.row)" type="text" size="small">查看</el-button>
   </template>
  </el-table-column>
 </el-table>

所以得到了angualr的table組件的格式:

<app-widget-table [data]="tableData">
  <app-widget-table-column prop="date" label="日期"></app-widget-table-column>

  <app-widget-table-column label="操作">
   <ng-template #scope let-row="scope">
      <ng-widget-button (click)="handleClick(row)" type="text" size="small">查看</el-button>
   </ng-template>
  </app-widget-table-column>
</app-widget-table>

在angular的table組件中,最爲困難就是ng-template如何將作用域綁定到ng-widget-button組件中;

關鍵點知識講解:

ng-content:
可以將父組件中所包含的所有子組件,都插入table組件中ng-container所在的位置,跟vue中的slot很像;

ng-container:
可以作爲一個組件的模板,跟vue裏面的template組件很像;

ng-template:
該東西,是整個組件中最爲麻煩的一個東西,直接使用它,會沒有任何效果,必須要和TemplateRef和ngTemplateOutlet一起使用,纔有有效果,主要是作爲模板並引入作用域,具體原理可以看一下官方文檔(https://www.angular.cn/api

TemplateRef:
主要是用來獲取ng-template組件的引用;

ngTemplateOutlet:
將ng-template的內容在html頁面展示出來,並綁定變量,就像vue中的router-view;

QueryList:
獲取table組件中所有的內容指引;

ContentChildren:
內容映射的接口,針對多個子元素採用

ContentChild:
內容映射的接口,針對單個子元素採用

先對app-widget-table-column組件進行分析:
該組件的作用就是爲了運輸數據,並且引入內容,該組件本身是不會有任何操作和邏輯,就是一個運輸工;

table-column.component.html:

<ng-container></ng-container>

table-column.component.ts:

import {Component, Input, Output, TemplateRef, ContentChild, AfterContentInit} from '@angular/core';

@Component({
  selector: 'app-widget-table-column',
  templateUrl: './table-column.component.html',
  styleUrls: ['./table-column.component.less'],
  preserveWhitespaces: false
})
export class TableColumnComponent implements AfterContentInit {
  constructor() {

  }

  @Input()
  label: string;

  @Input()
  prop: string;

  @Input()
  class: string;

  @Input()
  style: object;

  @ContentChild('scope') // 獲取ng-template組件的一個本地變量,並修飾scope對象
  scope: TemplateRef<any>; // 獲取ng-template的指引,主要是其內容,any表示該指可以是任何內容

  ngAfterContentInit(): void {}
}

table.component.html

<div>
  <div>
    <ng-content></ng-content> // 主要是用來引入整個table組件的內容,但不會在頁面顯示任何內容
  </div>

  <table class="table">
    <thead>
    <tr>
     <th *ngFor="let label of labelList">{{label}}</th>  // 類似於v-for,主要講table-cloumn的所有label蒐集,並展示
    </tr>
    </thead>

    <tbody *ngIf="data.length > 0">
    <ng-container *ngFor="let item of data; let i = index">
      <tr>
        <ng-container *ngFor="let row of tableColumn['_results']">
          <td *ngIf="row.prop" [ngStyle]="row.style" [ngClass]="row.class">{{item[row.prop]}}</td> // 直接展示

          <td *ngIf="row.scope" [ngStyle]="row.style" [ngClass]="row.class">
            <ng-container *ngTemplateOutlet="row.scope; context: {$implicit: {}, scope: data[i]}">
            </ng-container> // 展示ng-template的內容
          </td>
        </ng-container>
      </tr>
    </ng-container>
    </tbody>
  </table>

  <div *ngIf="data.length === 0" class="none-data">暫無數據!</div>
</div>

table.component.ts:

import {Component, OnInit, Input, Output, ContentChildren, AfterContentInit, ViewChild, AfterViewInit, QueryList} from '@angular/core';
import {TableColumnComponent} from '../table-column/table-column.component';

@Component({
  selector: 'app-widget-table',
  templateUrl: './table.component.html',
  styleUrls: ['./table.component.less'],
  preserveWhitespaces: false
})
export class TableComponent implements OnInit, AfterContentInit {
  constructor() {

  }

  @ContentChildren(TableColumnComponent)
  tableColumn: QueryList<TableColumnComponent>; // 獲取table-cloumn組件的所有實例

  @Input()
  data: object[];

  labelList: string[] = [];

  ngOnInit(): void {
    if (!(this.data instanceof Array)) {
      throw new Error('the data into TableComonent must be Array!');
    }
  }

  ngAfterContentInit(): void {
    this.labelList = this.tableColumn['_results'].map(item => item.label);
  }
}

雖然看起來這兩個組件的代碼不多,但裏面的邏輯卻比較繞,這也證明了ng用起來十分難上手,不過真的稱讚的是,ng採用ts和rx,用上手確實是比較爽。

這兩個組件目前還是比較粗糙,功能和特性也不是特別多,只能滿足一般表格的需求,後續會繼續完善該組件以及其他項目中用ng來開發的基礎組件,希望能沉澱出一套ng的組件庫。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持神馬文庫。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章