4.ng-zorro项目结构提取

396 阅读2分钟

结构优化

下面模块也展示为表格的增删改查,页面样式保持一致,这时候需要把不变的地方提出来,比如头部和底部,简化代码以方便后期使用。

在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对应的名称一定要和标签上名称一致。