小谈一下:
最近在国外的一些社区和网站上经常看到一个技术发展方向Bit,国外预测前端2020年的发展方向是组件公共化,大家可以上传自己开发的组件到bit,也可以直接下载复用别人的组件,并且无论组件是用Vue、Ng还是React开发的,都会被打包成一个js文件,直接在index.html导入即可实现复用,看似很神奇的一个东西,但是大量导入外部组件,一旦出错,维护成本将大大增加,开发者都清楚,修bug比写bug更累心,况且还是格式化过的代码...总之,目前bit上的资源数量和可利用量都很低,可能是大家还没有适应这种开发模式,或者是其他一些原因...下面我就Angular8,谈一下怎么在项目中开发并使用公共组件吧。
@Input() @Output() @Viewchild() @ContentChild()这些装饰器还熟悉吗?
不熟悉也没关系,只看概念真的能把人绕晕,还是实战让人理解地更快。所用到的也就是通过这些装饰器进行父子组件之间的通讯。记得vue这一块用的也是类似的方法,具体就不展开说了。先说一下这几个装饰器的作用吧。
以上装饰器是Angular的内置装饰器,也就是框架自带,初设的,不用我们再自己封装。
@Input
比如: @Input() dataSource: any;
定义在公共组件里,用来接收所调用者通过属性绑定传来的值,在公共组件OnInit里才能接收到。之后就可以当成变量用,但是是双向的,在公共组件里修改其值之后,调用者那边的值也随之改变,因此最好不要直接修改这个变量,先复制一份,去修改复制过的,保留元数据的clean。
@Output
比如:@Output() readonly sort: EventEmitter;
定义在公共组件里,用来导出在公共组件里触发的事件并导出参数。定义之后需要在构造器里先初始化一下
this.sort = new EventEmitter();
之后在所触发的事件中通过this.sort.emit(data);,传出参数数据。
@ContentChild
比如: @ContentChild(TemplateRef, { static: true }) tableActions: TemplateRef;
定义在公共组件里,用来接收调用者传入的template。这里需要在html里留出一个供template渲染的块
tableActions是template的Name,context是传出的数据;
调用时
下面提供一下源码:
公共组件 table.component.ts
import {
Component,
OnInit,
Input,
Output,
EventEmitter,
TemplateRef,
ContentChild,
SimpleChanges,
OnChanges
} from '@angular/core';
import { SelectionModel } from '@angular/cdk/collections';
import { MatDialog } from '@angular/material/dialog';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { MatTableDataSource } from '@angular/material/table';
export interface TableColumns {
field: string; // 字段
title: string; // 字段名
isShow?: boolean; // 是否显示
isSort?: boolean; // 可否排序
type?: ColumnType; // 类型
}
export enum ColumnType {
default, // 默认
slideToggle // slide滑动条
}
@Component({
selector: 'table',
templateUrl: './table.component.html',
styleUrls: ['./table.component.scss']
})
export class TableComponent implements OnInit, OnChanges {
selectionRow = new SelectionModel(true, []); // 选中的行
columnType: typeof ColumnType = ColumnType; // 定义Column类型枚举
renderedDataSource: any; // 转化后的数据
@Input() dataSource: any; // 远程数据
@Input() placeholder: string; // // 默认提示
@Input() checkable: boolean; // // 是否出现复选框
@Input() hiddenCheckHead: boolean; // // 是否隐藏复选框title
@Input() columns: TableColumns[]; // 远程列名
@Output() readonly checkChange: EventEmitter; // 复选框点击事件传出选中元素
@Output() readonly sort: EventEmitter; // 复选框点击事件传出选中元素
@ContentChild(TemplateRef, { static: true }) tableActions: TemplateRef; // 子组件的模板
constructor(public dialog: MatDialog, public httpClient: HttpClient) {
this.checkChange = new EventEmitter();
this.sort = new EventEmitter();
this.checkable = false;
this.placeholder = '抱歉!没有搜索到任何结果';
this.columns = [];
this.renderedDataSource = new MatTableDataSource([]);
this.hiddenCheckHead = true;
}
/**
* when data change trigger
* @param changes changed data
*/
ngOnChanges(changes: SimpleChanges): any {
if (changes['dataSource']) {
this.renderedDataSource = new MatTableDataSource(this.dataSource);
}
}
/**
* init the columns
*/
ngOnInit(): any {
this.columns.forEach((v, i, arr) => {
if (!v.isShow) {
arr.splice(i, 1);
this.columns = arr;
}
});
if (this.tableActions) {
this.columns.push({
field: 'actions',
title: '操作',
isShow: true,
isSort: false,
type: ColumnType.default
});
}
if (this.checkable) {
this.columns.unshift({
field: 'check',
title: '选择',
isShow: true,
isSort: false,
type: ColumnType.default
});
}
}
/**
* Whether the number of selected elements matches the total number of rows.
*/
isAllSelected(): any {
const numSelected = this.selectionRow.selected.length;
const numRows = this.renderedDataSource.data.length;
return numSelected === numRows;
}
/**
* Selects all rows if they are not all selected; otherwise clear selection.
*/
masterToggle(): any {
this.isAllSelected()
? this.selectionRow.clear()
: this.renderedDataSource.data.forEach((row: any) => {
this.selectionRow.select(row);
});
}
/**
* click single row and output the event
* @param row checked row
*/
checkChanged(row?: any): any {
this.checkChange.emit(this.selectionRow.selected);
}
/**
* The label for the checkbox on the passed row
* @param row checked data
*/
checkboxLabel(row?: any): string {
if (!row) {
return `${this.isAllSelected() ? 'select' : 'deselect'} all`;
} else {
return `${
this.selectionRow.isSelected(row) ? 'deselect' : 'select'
} row ${row.ID + 1}`;
}
}
sorted(data: any): any {
this.sort.emit(data);
}
}
table.component.html
{{ col.title }}
{{ row[col.field] }}
call.component.html
call.component.ts (部分代码)
tableDatasource: any; // table数据
tableColumns: TableColumns[]; // table column
checkable: boolean;
----------
checkChanged(data: any){
console.log(data);
}
onSorted(data: any){
console.log(data)
}
好了,到这一个公共表格就开发完成了。有问题欢迎共同探讨。