带有(可选)动画的角度组件拖放

发布于 2025-01-11 08:56:00 字数 321 浏览 1 评论 0原文

我正在尝试构建一个主/仪表板页面,如下图所示。我想要实现的是能够拖放标记为 1-6 的组件(它们都是单独的组件)。我不确定是否可以使用有角度的 CDK 拖放来实现此功能。我想做的另一件事是有某种拖放动画,在页面加载时,一些组件会切换位置。

有人可以告诉我这是否可以使用 Angular CDK 拖放来实现,或者我是否需要使用一些外部包?

输入图片此处描述

I'm trying to build a main/dashboard page like the image given below. What I am trying to achieve is to be able to drag and drop the components labeled from 1-6 (they will all be separate components). I'm not sure if angular CDK drag and drop can be used to achieve this functionality. One more thing I'm trying to do is have some sort of drag and drop animation where on page load, a few components switch positions.

Can someone let me know if this is possible using angular CDK drag and drop or will I need to use some external package?

enter image description here

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

情域 2025-01-18 08:56:00

确实有点复杂,但是让我们开始吧。

分发一系列组件时我们首先需要考虑的是我们可以使用任何方式。我选择使用 Bootstrap 4 中的“masonary”(但您可以根据自己的选择进行制作)

当我们拖动 cdkList 并且它不是水平或垂直分布时,否则我们会遇到问题的“网格”。所以我选择创建一系列具有唯一元素的cdkDropList。但由于我不想在拖动时移动,因此拖动时我将其置于绝对位置。所以我们的数组项就像

[{data:1,style:null},{data:2,style:null}] 

当我们要拖动时,我们计算位置。为此,我们需要使用 ViewChildren 来获取 cdkDragList,但使用 {read:ElementRef} 因为我们只对 ElementRef 感兴趣

  @ViewChildren(CdkDropList,{read:ElementRef}) cards:QueryList<ElementRef>
  wrapperStyle={width:'',height:''}
  calculePosition()
  {
    let width=0;
    let height=0;
    this.cards.forEach((x,index)=>{
       const rect=x.nativeElement.getBoundingClientRect()
       if (width<rect.left+rect.width)
        width=rect.left+rect.width;
        if (height<rect.top+rect.height)
        height=rect.top+rect.height;

       this.items[index].style={
         position:'absolute',
         top:rect.top+'px',
         left:rect.left+'px',
         width:rect.width+'px',
         height:rect.height+'px'
       }
       this.onDrag=true;
    })
    this.wrapperStyle={width:width+'px',height:height+'px'}
  }

我们的 .html 可以像

<div [ngStyle]="onDrag?wrapperStyle:null" cdkDropListGroup 
        [ngClass]="onDrag?'position-relative':'card-columns'">
  <ng-container *ngFor="let item of items;let index=index">
    <div [ngStyle]="onDrag?item.style:null"
      cdkDropList
      orientation="vertical"
      cdkDropListSortingDisabled="true"
      [cdkDropListData]="index"
      (cdkDropListDropped)="drop($event)"
    >
      <div class="card" cdkDrag (mousedown)="calculePosition()" >
        <div #place>
        </div>
        <div *cdkDragPlaceholder></div>
      </div>
    </div>
  </ng-container>
</div>

查看如何使用变量“onDrag”我们使用绝对位置或不使用绝对位置。另请参阅,我们将组件的“索引”作为“数据”。这让我们的函数 drop 变得像

  drop(event: CdkDragDrop<any,any>) {
    
    const currentIndex=event.container.data;
    const previousIndex=event.previousContainer.data;
    this.items=this.items.map((x,i)=>{

        if (i==previousIndex)
        return this.items[currentIndex]
        if (i==currentIndex)
        return this.items[previousIndex]
        return x
    })
    this.onDrag=false;
  }

只需要附加到我们的“#place”组件(基于“item.data”)

为此,首先使用 viewChildren 和 read:ViewContainerRef 并使用 AfterViewInit

  @ViewChildren('place', { read: ViewContainerRef }) places: QueryList<ViewContainerRef>
  ngAfterViewInit()
  {
    this.places.forEach((x,index)=>{
      switch (this.items[index].data)
      {
          case 0:
            x.createComponent(HelloComponent)
            break;
            default:
              x.createComponent(ByComponent)
              break;
        }
    })
  }

a 小stackblizt

注意:您只需要在本地存储中存储数组“items”即可“保存配置”

Really it's a bit complex but let's go

The first we need take account to distribute a series of component is that we can use any way. I choose use "masonary" from bootstrap 4 (but you can make as you choose)

When we drag a cdkList and this is not distributed horizontal or vertical else a "grid" we enter in problems. so I choose create a series of cdkDropList with an unique element. But as I want not move while I'm dragging, when is dragging I put in a position absolute. So our array items will be like

[{data:1,style:null},{data:2,style:null}] 

And when we are going to drag, we calcule the positions. For this, we need use ViewChildren to get the cdkDragList, but use {read:ElementRef} because we are only interested in the ElementRef

  @ViewChildren(CdkDropList,{read:ElementRef}) cards:QueryList<ElementRef>
  wrapperStyle={width:'',height:''}
  calculePosition()
  {
    let width=0;
    let height=0;
    this.cards.forEach((x,index)=>{
       const rect=x.nativeElement.getBoundingClientRect()
       if (width<rect.left+rect.width)
        width=rect.left+rect.width;
        if (height<rect.top+rect.height)
        height=rect.top+rect.height;

       this.items[index].style={
         position:'absolute',
         top:rect.top+'px',
         left:rect.left+'px',
         width:rect.width+'px',
         height:rect.height+'px'
       }
       this.onDrag=true;
    })
    this.wrapperStyle={width:width+'px',height:height+'px'}
  }

Our .html can be like

<div [ngStyle]="onDrag?wrapperStyle:null" cdkDropListGroup 
        [ngClass]="onDrag?'position-relative':'card-columns'">
  <ng-container *ngFor="let item of items;let index=index">
    <div [ngStyle]="onDrag?item.style:null"
      cdkDropList
      orientation="vertical"
      cdkDropListSortingDisabled="true"
      [cdkDropListData]="index"
      (cdkDropListDropped)="drop($event)"
    >
      <div class="card" cdkDrag (mousedown)="calculePosition()" >
        <div #place>
        </div>
        <div *cdkDragPlaceholder></div>
      </div>
    </div>
  </ng-container>
</div>

See how with the variable "onDrag" we use position absolute or not. See also that as "data" we put the "index" of the component. This allow us our function drop becomes like

  drop(event: CdkDragDrop<any,any>) {
    
    const currentIndex=event.container.data;
    const previousIndex=event.previousContainer.data;
    this.items=this.items.map((x,i)=>{

        if (i==previousIndex)
        return this.items[currentIndex]
        if (i==currentIndex)
        return this.items[previousIndex]
        return x
    })
    this.onDrag=false;
  }

Just only need attach to our "#place" the components (based in the "item.data")

For this, first use viewChildren with read:ViewContainerRef and use AfterViewInit

  @ViewChildren('place', { read: ViewContainerRef }) places: QueryList<ViewContainerRef>
  ngAfterViewInit()
  {
    this.places.forEach((x,index)=>{
      switch (this.items[index].data)
      {
          case 0:
            x.createComponent(HelloComponent)
            break;
            default:
              x.createComponent(ByComponent)
              break;
        }
    })
  }

a little stackblizt

NOTE: You only need store in the localstore the array "items" to "save the configuration"

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文