File

src/app/layout/html-builder/component/ch/ch-grid/ch-grid.component.ts

Implements

OnInit

Metadata

encapsulation ViewEncapsulation.None
selector app-ch-grid
styleUrls ./ch-grid.component.less
templateUrl ./ch-grid.component.html

Index

Properties
Methods
Inputs

Constructor

constructor(pageEditorService: PageEditorService, nzContextMenuService: NzContextMenuService)
Parameters :
Name Type Optional
pageEditorService PageEditorService No
nzContextMenuService NzContextMenuService No

Inputs

gridItem
Type : DropItem
itemIndex
Type : number
itemParent
Type : DropItem[]

Methods

Public click
click()
Returns : void
Public contextMenu
contextMenu(event: MouseEvent, menu: NzDropdownMenuComponent)
Parameters :
Name Type Optional
event MouseEvent No
menu NzDropdownMenuComponent No
Returns : void
Public copy
copy()
Returns : void
Public delete
delete()
Returns : void
Public drop
drop(event: CdkDragDrop)
Parameters :
Name Type Optional
event CdkDragDrop<DropItem> No
Returns : void
Public initColData
initColData()
Returns : void
Public ngOnInit
ngOnInit()
Returns : void
Public split
split(n: number)
Parameters :
Name Type Optional
n number No
Returns : void

Properties

Public colItemsTemp
Type : ColItem[]
Public pageEditorService
Type : PageEditorService
Public schema
Type : SFSchema
Default value : { properties: { layout: { type: 'array', title: '栅格布局', minItems: 1, maxItems: 12, description: '* 栅格布局,基于Boostrap,24分格。', items: { type: 'object', properties: { pc: { type: 'number', title: '桌面', minimum: 1, maximum: 24, default: 4, }, pad: { type: 'number', title: '平板', minimum: 1, maximum: 24, default: 4, }, phone: { type: 'number', title: '手机', minimum: 1, maximum: 24, default: 4, }, padding: { type: 'string', title: '左右边距', enum: [ { label: '默认', value: '' }, { label: '左边距:0', value: 'pl0' }, { label: '右边距:0', value: 'pr0' }, { label: '两边距:0', value: 'px0' }, ], default: '', }, }, }, ui: { grid: { arraySpan: 8 }, }, }, }, }
import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
import { Component, Input, OnInit, ViewEncapsulation } from '@angular/core';
import { SFSchema } from '@delon/form';
import { NzContextMenuService, NzDropdownMenuComponent } from 'ng-zorro-antd/dropdown';
import { ColItem, DropItem, PageEditorService } from 'src/app/layout/html-builder/page-editor/page-editor.service';

@Component({
  selector: 'app-ch-grid',
  templateUrl: './ch-grid.component.html',
  styleUrls: ['./ch-grid.component.less'],
  encapsulation: ViewEncapsulation.None
})
export class ChGridComponent implements OnInit {

  public schema: SFSchema = {
    properties: {
      layout: {
        type: 'array',
        title: '栅格布局',
        minItems: 1,
        maxItems: 12,
        description: '* 栅格布局,基于Boostrap,24分格。',
        items: {
          type: 'object',
          properties: {
            pc: {
              type: 'number',
              title: '桌面',
              minimum: 1,
              maximum: 24,
              default: 4,
            },
            pad: {
              type: 'number',
              title: '平板',
              minimum: 1,
              maximum: 24,
              default: 4,
            },
            phone: {
              type: 'number',
              title: '手机',
              minimum: 1,
              maximum: 24,
              default: 4,
            },
            padding: {
              type: 'string',
              title: '左右边距',
              enum: [
                { label: '默认', value: '' },
                { label: '左边距:0', value: 'pl0' },
                { label: '右边距:0', value: 'pr0' },
                { label: '两边距:0', value: 'px0' },
              ],
              default: '',
            },
          },
        },
        ui: {
          grid: { arraySpan: 8 },
        },
      },
    },
  };

  @Input()
  public gridItem: DropItem;

  @Input()
  public itemIndex: number;

  @Input()
  public itemParent: DropItem[];

  // 格子分列数据
  public colItemsTemp: ColItem[];

  constructor(
    public pageEditorService: PageEditorService,
    private nzContextMenuService: NzContextMenuService,
  ) { }

  public initColData() {
    // console.log('initColData');
    // 连接拖放组件
    if (!this.gridItem.data.layout) {
      this.gridItem.data.layout = [
        { pc: 12, pad: 12, phone: 24 },
        { pc: 12, pad: 12, phone: 24 },
      ];
    }
    this.colItemsTemp = this.pageEditorService.updateDropConnect(this.gridItem.data.layout);
    // 初始化ch-grid栅格数据
    if (this.gridItem.colItems.length) {
      this.colItemsTemp.forEach((_, index: number) => {
        if (this.gridItem.colItems[index]) {
          this.colItemsTemp[index].dropItems = this.gridItem.colItems[index].dropItems;
        }
      });
    }
    this.gridItem.colItems = this.colItemsTemp;
    // console.log(this.pageEditorService.dropItems, this.gridItem);
  }

  // 拖放组件
  public drop(event: CdkDragDrop<DropItem>) {
    // console.log('In ChGridComponent');
    // console.log(`previousIndex => ${event.previousIndex}, currentIndex => ${event.currentIndex}`);
    // console.log('previousContainer.data => ', event.previousContainer.data);
    this.gridItem.colItems.forEach((colItem: ColItem) => {
      if (event.container.id === colItem.id) {
        if (event.previousContainer === event.container) {
          moveItemInArray(colItem.dropItems, event.previousIndex, event.currentIndex);
        } else {
          if (this.gridItem.rootUid === undefined) {
            this.gridItem.rootUid = this.gridItem.uid;
          }
          colItem.dropItems.splice(event.currentIndex, 0, new DropItem(event.previousContainer.data.code, undefined,
            this.gridItem.rootUid));
        }
      }
    });
  }

  // 右键菜单
  public contextMenu(event: MouseEvent, menu: NzDropdownMenuComponent): void {
    event.stopPropagation();
    event.stopImmediatePropagation();
    this.nzContextMenuService.create(event, menu);
  }

  // 分割栅格
  public split(n: number) {
    if (n !== this.gridItem.data.layout.length) {
      switch (n) {
        case 2:
          this.gridItem.data.layout = this.gridItem.data.layout = [
            { pc: 12, pad: 12, phone: 24 },
            { pc: 12, pad: 12, phone: 24 },
          ];
          break;
        case 3:
          this.gridItem.data.layout = this.gridItem.data.layout = [
            { pc: 8, pad: 8, phone: 24 },
            { pc: 8, pad: 8, phone: 24 },
            { pc: 8, pad: 8, phone: 24 },
          ];
          break;
        case 4:
          this.gridItem.data.layout = this.gridItem.data.layout = [
            { pc: 6, pad: 6, phone: 24 },
            { pc: 6, pad: 6, phone: 24 },
            { pc: 6, pad: 6, phone: 24 },
            { pc: 6, pad: 6, phone: 24 },
          ];
          break;
      }
      this.initColData();
      this.click();
    }
  }

  // 复制组件
  public copy() {
    this.pageEditorService.copyDropItem(this.itemIndex);
  }

  // 删除组件
  public delete() {
    this.pageEditorService.removeDropItem(this.itemIndex);
  }

  // 点击打开属性
  public click() {
    this.pageEditorService.updatePropForm(this.schema, this.gridItem);
  }

  public ngOnInit() {
    this.initColData();
  }

}
<div class="playground row mb2" (contextmenu)="contextMenu($event, menu)" [ngClass]="gridItem.data | props"
  (click)="click()">
  <div *ngFor="let colItem of gridItem.colItems, let i=index"
    [class]="'col-md-'+colItem.pc+' '+'col-sm-'+colItem.pad+' '+'col-xs-'+colItem.phone"
    [ngClass]="{'pl0': gridItem.data.layout[i].padding === 'pl0','pr0': gridItem.data.layout[i].padding === 'pr0','px0': gridItem.data.layout[i].padding === 'px0'}">
    <div class="col-wrapper" [id]="colItem.id" cdkDropList (cdkDropListDropped)="drop($event)">
      <div class="playground-item" *ngFor="let item of colItem.dropItems; index as i;" cdkDrag>
        <app-ch-head #player [item]="item" [itemIndex]="i" [itemParent]="colItem.dropItems"
          *ngIf="item.code === 'app-ch-head'">
        </app-ch-head>
        <app-ch-p #player [item]="item" *ngIf="item.code === 'app-ch-p'">
        </app-ch-p>
        <app-ch-list #player [item]="item" *ngIf="item.code === 'app-ch-list'">
        </app-ch-list>
        <app-ch-link #player [item]="item" *ngIf="item.code === 'app-ch-link'">
        </app-ch-link>
        <app-ch-img #player [item]="item" *ngIf="item.code === 'app-ch-img'">
        </app-ch-img>
        <app-ch-carousel #player [item]="item" *ngIf="item.code === 'app-ch-carousel'">
        </app-ch-carousel>
        <app-ch-info-card #player [item]="item" *ngIf="item.code === 'app-ch-info-card'">
        </app-ch-info-card>
        <app-ch-tour-card #player [item]="item" *ngIf="item.code === 'app-ch-tour-card'">
        </app-ch-tour-card>
        <app-ch-tailormade-form #player [item]="item" *ngIf="item.code === 'app-ch-tailormade-form'">
        </app-ch-tailormade-form>
        <app-ch-tour-form #player [item]="item" *ngIf="item.code === 'app-ch-tour-form'">
        </app-ch-tour-form>
        <div class="preview-holder" *cdkDragPreview>我只是一个无情的占位符</div>
        <div class="custom-placeholder" *cdkDragPlaceholder></div>
      </div>
      <span class="col-uid">{{ colItem.id }}</span>
    </div>
  </div>
</div>
<nz-dropdown-menu #menu="nzDropdownMenu">
  <ul nz-menu class="grid-context-ment">
    <li nz-menu-item>栅格布局 <i nz-icon nzType="question-circle" nzTheme="twotone"></i></li>
    <li nz-menu-divider></li>
    <li nz-submenu nzTitle="快速分格">
      <ul>
        <li nz-menu-item (click)="split(2)">两列布局</li>
        <li nz-menu-item (click)="split(3)">三列布局</li>
        <li nz-menu-item (click)="split(4)">四列布局</li>
      </ul>
    </li>
    <li nz-menu-item (click)="copy()">复制整行</li>
    <li nz-menu-item (click)="delete()">删除整行</li>
  </ul>
</nz-dropdown-menu>

./ch-grid.component.less

.col-wrapper {
  min-height: 128px;
  box-shadow: 0 0 1px brown;
  position: relative;

  .col-uid {
    position: absolute;
    right: -24px;
    top: 0;
    padding: 4px;
    background: #000;
    opacity: 0.3;
    color: #fff;
    font-size: 0.9rem;
    width: 24px;
    writing-mode: vertical-lr;
    line-height: normal;
    border-radius: 0 4px 4px 0;
    cursor: default;
    display: none;
  }
}

.light {
  border: 1px solid lightgreen;
}

/* 拖放动画 */
.cdk-drag-preview {
  box-sizing: border-box;
  border-radius: 4px;
  box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
    0 8px 10px 1px rgba(0, 0, 0, 0.14),
    0 3px 14px 2px rgba(0, 0, 0, 0.12);
}

.cdk-drag-placeholder {
  opacity: 0;
}

.cdk-drag-animating {
  transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}

.col-wrapper.cdk-drop-list-dragging .playground-item:not(.cdk-drag-placeholder) {
  transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}

.cdk-drop-list-dragging {
  background: #f1f1f1;

  .col-uid {
    background: darkgreen;
  }
}

.preview-holder.cdk-drag-preview {
  height: 48px;
  line-height: 48px;
  padding: 0 12px;
  border: 1px solid #333;
  background: #fff;
}

.custom-placeholder {
  background: #ccc;
  border: dotted 3px #999;
  height: 48px;
  transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
  opacity: 1;
}

.preview-holder.cdk-drag-preview {
  height: 48px;
  line-height: 48px;
  padding: 0 12px;
  border: 1px solid #333;
  background: #fff;
}

.custom-placeholder {
  background: #ccc;
  border: dotted 3px #999;
  height: 48px;
  transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
  opacity: 1;
}
Legend
Html element
Component
Html element with directive

result-matching ""

    No results matching ""