结构优化
下面模块也展示为表格的增删改查,页面样式保持一致,这时候需要把不变的地方提出来,比如头部和底部,简化代码以方便后期使用。
在shared模块中执行命令新建components文件夹,并生成widget-panel组件
ng g c components/widget-panel
生成完成后,将头部和底部放入widget-panel组件中:
widget-panel.component.html
<div class="widget-container">
<nz-breadcrumb nzAutoGenerate="true"></nz-breadcrumb>
<ng-content></ng-content>
<div class="g-footer">
<nz-space>
<nz-space-item>
<button nz-button [nzType]="'primary'" [disabled]="!btnActive" (click)="activeHandle()">启用</button>
</nz-space-item>
<nz-space-item>
<button nz-button [nzType]="'primary'" [disabled]="!btnDisabled" (click)="disabledHandle()">禁用</button>
</nz-space-item>
</nz-space>
</div>
</div>
widget-panel.component.ts
import { Component, Input, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-widget-panel',
templateUrl: './widget-panel.component.html',
styleUrls: ['./widget-panel.component.css']
})
export class WidgetPanelComponent {
@Input() btnDisabled = true;
@Input() btnActive = true;
@Output() activeEvent = new EventEmitter();
@Output() disabledEvent = new EventEmitter();
constructor() { }
activeHandle(): void {
this.activeEvent.emit();
}
disabledHandle(): void {
this.disabledEvent.emit();
}
}
widget-panel.component.css
:host .widget-container {
position: relative;
height: 100%;
width: 100%;
padding: 10px;
overflow: hidden;
}
:host .ant-breadcrumb {
font-size: 20px;
font-weight: bold;
}
:host .g-footer {
position: absolute;
bottom: 0px;
right: 0px;
width: 100%;
text-align: right;
line-height: 50px;
background: #ddd;
}
shared.module中的引用位置稍做修改
shared.module.ts
import { WidgetAddComponent } from './components/widget-add/widget-add.component';
...
// 公共组件
const COMPONENTS = [
WidgetPanelComponent,
];
这样就把相同的位置抽离出来,使用的时候只需要用标签直接使用即可。
修改app/routes/profession/profession-list组件
profession-list.component.html
<app-widget-panel [btnDisabled]="btnDisabled" [btnActive]="btnActive" (activeEvent)="clickHandle('A')"
(disabledEvent)="clickHandle('D')">
<p>profession-list works!</p>
</app-widget-panel>
profession-list.component.ts
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-profession-list',
templateUrl: './profession-list.component.html',
styleUrls: ['./profession-list.component.css']
})
export class ProfessionListComponent implements OnInit {
btnDisabled = true;
btnActive = true;
constructor() {}
ngOnInit(): void {
}
clickHandle(type: string): void {
console.warn(type);
}
}
此时profession-list组件中就可以展示固定的头部和底部。
代码解析:
ng-content
widget-panel组件生成完成后,在使用时中间内容默认会投影到ng-content标签中。
<app-widget-panel>中间内容</app-widget-panel>
<div class="widget-container">
...
<ng-content></ng-content>
...
</div>
如果页面中有多个ng-content,默认会投影到第一个中,如果需要指定投影,只需要添加对应select即可,select属性支持css选择器(#id、.class、div),会匹配所有的。
<div class="widget-container">
...
<ng-content></ng-content>
<ng-content select='#btn'></ng-content>
...
</div>
<app-widget-panel>
<div id="btn">btn</div>
...
</app-widget-panel>
id为btn的会放入第二个ng-content,其余的放入第一个ng-content中。
==注意:选择器必须是直接子元素,否则无效。==
<app-widget-panel>
<div class="btn">btn</div>
<div>
<div class="btn">btn</div>
</div>
...
</app-widget-panel>
样式选取的时候,不会识别第二个btn样式。
@Input()和@Output()
在组件使用过程中,需要把可变属性和对应方法传递给父组件,父组件需要接受属性和输出方法。
@Input() btnDisabled = true;
@Input() btnActive = true;
@Output() activeEvent = new EventEmitter();
@Output() disabledEvent = new EventEmitter();
<app-widget-panel [btnDisabled]="btnDisabled" [btnActive]="btnActive" (activeEvent)="clickHandle('A')"
(disabledEvent)="clickHandle('D')">
</app-widget-panel>
@input可以直接设置对应的值,如果外部没有传入就会使用默认值
@Input() btnDisabled = true;
接受app-widget-panel标签上面的btnDisabled的值,如果值是变量,每次变化widget组件内部也会跟着变化。
@Output() activeEvent = new EventEmitter();
this.activeEvent.emit();
事件推送,widget内部有事件变动需要通知子元素,通过emit推送,子元素只需要处理clickHandle方法即可。
@Output对应的名称一定要和标签上名称一致。