Zee*_*qui 4 drag-and-drop typescript angular-material angular
参考 Angular CDK 拖放,我尝试创建一个带有左侧边栏和主要内容区域的简单仪表板。这两个区域都将包含独特的自定义组件,这些组件需要可拖动,并且可以在其包含的区域内重新排序并转移到另一个区域。
例如。侧边栏包含Comp和Comp1,然后我可以在该区域内重新排序它们并将它们转移到主要内容区域。
据我了解,Angular Material CDK 拖放仅适用于列表。此外,列表中的项目必须具有相似的类型才能重新排序/转移。
有没有办法利用CDKDragandCDKDropList来处理静态项而不是数组中的项?我无法重新排序自定义组件或将其转移到不同的下拉列表。
我创建了一个示例项目:https://stackblitz.com/edit/ng-mat-dnd 演示:https://ng-mat-dnd.stackblitz.io/
应用程序组件.html
<div class="example-container">
<h2>Sidebar</h2>
<div cdkDropList #sidebarList="cdkDropList" [cdkDropListData]="sidebar" cdkDropListConnectedTo="[mainList]"
class="example-list" (cdkDropListDropped)="drop($event)">
<div class="example-box" cdkDrag>
<app-demo-comp-2 [btn]=2></app-demo-comp-2>
</div>
<div class="example-box" cdkDrag>
<app-demo-comp [ddn]=2></app-demo-comp>
</div>
<div class="example-box" cdkDrag>
<app-demo-comp-3 [txt]=3></app-demo-comp-3>
</div>
</div>
</div>
<div class="example-container">
<h2>Main</h2>
<div cdkDropList #mainList="cdkDropList" [cdkDropListData]="main" cdkDropListConnectedTo="[sidebarList]"
class="example-list" (cdkDropListDropped)="drop($event)">
<div class="example-box" cdkDrag>
<app-demo-comp [ddn]=1></app-demo-comp>
</div>
<div class="example-box" cdkDrag>
<app-demo-comp-2 [btn]=3></app-demo-comp-2>
</div>
</div>
</div>
Run Code Online (Sandbox Code Playgroud)
应用程序组件.ts
import { Component, OnInit, ViewChildren, QueryList } from '@angular/core';
import { CdkDragDrop, moveItemInArray, transferArrayItem, CdkDrag } from '@angular/cdk/drag-drop';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
sidebar;
main;
@ViewChildren(CdkDrag) draggables: QueryList<CdkDrag>;
constructor() { }
ngOnInit() { }
ngAfterViewInit() {
console.log(this);
this.sidebar = [this.draggables.toArray()[0], this.draggables.toArray()[1], this.draggables.toArray()[2]];
console.log(this.sidebar);
this.main = [this.draggables.toArray()[4], this.draggables.toArray()[3]];
console.log(this.main);
}
drop(event: CdkDragDrop<any[]>) {
console.log(event);
if (event.previousContainer === event.container) {
console.log('Same container');
moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
} else {
console.log('Different containers');
transferArrayItem(event.previousContainer.data,
event.container.data,
event.previousIndex,
event.currentIndex);
}
}
}
Run Code Online (Sandbox Code Playgroud)
Angular Material cdk 拖放功能的工作原理是恢复元素的可见性并将其插入到DOM 中的旧位置。
它们保持位置很重要,因为它们依赖ngFor指令并在 DOM 中移动元素可能会导致NgFor智能差异并仅在必要时重新创建元素。
这意味着如果你想让它在没有 ngFor 的情况下工作,那么你必须自己移动 html 元素。
以下是如何完成此操作的示例:
drop(event: CdkDragDrop<any[]>) {
const nodeToMove = event.item.element.nativeElement;
const { previousContainer, container, previousIndex, currentIndex } = event;
console.log(this.sidebar, this.main);
if (previousContainer === container) {
moveItemInArray(container.data, previousIndex, currentIndex);
moveWithinContainer(
container.element.nativeElement,
previousIndex,
currentIndex
);
} else {
transferArrayItem(
previousContainer.data,
container.data,
previousIndex,
currentIndex
);
transferNodeToContainer(
nodeToMove,
container.element.nativeElement,
currentIndex
);
Promise.resolve().then(() => {
previousContainer.removeItem(event.item);
event.item.dropContainer = container;
event.item._dragRef._withDropContainer(container._dropListRef);
container.addItem(event.item);
});
}
}
...
function moveWithinContainer(container, fromIndex, toIndex) {
if (fromIndex === toIndex) {
return;
}
const nodeToMove = container.children[fromIndex];
const targetNode = container.children[toIndex];
if (fromIndex < toIndex) {
targetNode.parentNode.insertBefore(nodeToMove, targetNode.nextSibling);
} else {
targetNode.parentNode.insertBefore(nodeToMove, targetNode);
}
}
function transferNodeToContainer(node, container, toIndex) {
if (toIndex === container.children.length) {
container.appendChild(node);
} else {
const targetItem = container.children[toIndex];
targetItem.parentNode.insertBefore(node, targetItem);
}
}
Run Code Online (Sandbox Code Playgroud)
您可能已经注意到,上面的解决方案有点hacky,并且可能会根据库版本而被破坏。
你可以做的是使用 ngFor 指令代替:
ts
sidebar = [0, 1, 2];
main = [0, 1];
Run Code Online (Sandbox Code Playgroud)
html
<div *ngFor="let item of sidebar" class="example-box" cdkDrag>
<app-demo-comp-2 *ngIf="item === 0" [btn]=2></app-demo-comp-2>
<app-demo-comp *ngIf="item === 1" [ddn]=2></app-demo-comp>
<app-demo-comp-3 *ngIf="item === 2" [txt]=3></app-demo-comp-3>
</div>
...
<div *ngFor="let item of main" class="example-box" cdkDrag>
<app-demo-comp *ngIf="item === 0" [ddn]=1></app-demo-comp>
<app-demo-comp-2 *ngIf="item === 1" [btn]=3></app-demo-comp-2>
</div>
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
10914 次 |
| 最近记录: |