Angular 在角度方向上设置两个或多个DIV位置的动画

Angular 在角度方向上设置两个或多个DIV位置的动画,angular,Angular,我需要帮助任意匹配动态渲染的2个或更多div的位置开关。 下面是一个简单的例子: let objects: Array<number> = []; objects.push(1); objects.push(2); let对象:数组=[]; 物体。推(1); 物体。推(2); 模板: <div *ngFor="let obj of objects"> content {{object}} </div> 内容{{object}

我需要帮助任意匹配动态渲染的2个或更多div的位置开关。 下面是一个简单的例子:

let objects: Array<number> = [];
objects.push(1);
objects.push(2);
let对象:数组=[];
物体。推(1);
物体。推(2);
模板:

<div *ngFor="let obj of objects">
    content {{object}}
</div>

内容{{object}
从模板中,用户可以更改对象的位置,将对象“1”移动到第二个位置,对象“2”将成为第一个位置

我需要一个动画来清楚地向用户显示运动。实际上,DOM中的结果是:

之前:

<div>
   content 1
</div>
<div>
  content 2
</div>

内容1
内容2
之后:

<div>
   content 2
</div>
<div>
  content 1
</div>

内容2
内容1
结果是通过修改源阵列、更改元素位置获得的

我可以使用哪种解决方案?我可以使用更复杂的对象来处理这个问题,这样我就可以在需要时修改代码


谢谢

我研究后的最佳解决方案是使用cdk/拖放您可以导入此库并使用它拖放元素

您只需在代码中添加以下行,就可以了

.ts文件应包含以下代码

export class CdkDragDropSortingExample {
  movies = [
    'Episode I - The Phantom Menace',
    'Episode II - Attack of the Clones'
  ];

  drop(event: CdkDragDrop<string[]>) {
    moveItemInArray(this.movies, event.previousIndex, event.currentIndex);
  }
}

我不知道这是否是一个好的解决方案,但这是我唯一能想象的。我的想法是用绝对位置保存div的“副本”,并用不透明度=0或可见性=隐藏保持“原始”。当更改数组时,用setTimeout制作一个手动动画,更改“副本”的顶部和左侧

用密码。假设您有一个数组数据

data:any[]=[1,2,3,4,5]
类似html的

<div >
  <ng-container *ngFor="let item of data;let i=index">
    <div #origin style="opacity:0" >{{item}}</div>
    <div #copy  style="position:absolute" [style.z-index]="i" >{{item}}</div>
  </ng-container>
</div>
你可以在地图上看到

更新为什么不制定指令

更新2我使用offsetTop和offsetLeft并添加window.scrollX和window.scrollY更新指令。此外,我还添加了一个新属性:pos0,如果为true,则首先在pos 0,0中创建“copy”

@Directive({ selector: "[animate]" })
export class AnimateDirective implements OnInit {
  original: any;
  copy: any;
  timing:string;
  private player: AnimationPlayer;

  @Input() set animate(value: string) {
    this.timing = value || "450ms ease-in-out";
  }
  @Input('animatePos0') pos0:boolean=false;

  constructor(
    private templateRef: TemplateRef<any>,
    private viewContainer: ViewContainerRef,
    private builder: AnimationBuilder,
    private renderer: Renderer2
  ) {}

  ngOnInit() {
    this.original = this.viewContainer.createEmbeddedView(
      this.templateRef
    ).rootNodes[0];
    setTimeout(() => {
      this.copy = this.viewContainer.createEmbeddedView(
        this.templateRef
      ).rootNodes[0];
      this.renderer.setStyle(this.original, "visibility","hidden");
      const rect = !this.pos0?
          {top:this.original.offsetTop,left:this.original.offsetLeft}:
          {top:0,left:0};
      this.renderer.setStyle(this.copy, "position", "absolute");
      this.renderer.setStyle(this.copy, "top", rect.top+ window.scrollY + "px");
      this.renderer.setStyle(this.copy, "left", rect.left+ window.scrollX + "px");
    });
  }
  animateGo() {
    setTimeout(() => {
      const rect = {top:this.original.offsetTop,left:this.original.offsetLeft}
      const myAnimation = this.builder.build([
        animate(this.timing, 
          style({ top: rect.top+ window.scrollY, 
                  left: rect.left+ window.scrollX }))
      ]);
      this.player = myAnimation.create(this.copy);
      this.player.play();
    });
  }
}

看a

这个解决方案很好,我喜欢@请小心,我忘了添加window.scrollX和window.scrollY。我也不确定是使用GetBoundClientre还是offsetTop以及原始版本的OffsetLeft。无论如何,我对物体的“边缘”有困难。我不太确定是否能按时纠正这个问题。我用它改进了stackblitz,并在添加时为“animate”添加了一个新属性“pos0”
<div >
  <ng-container *ngFor="let item of data;let i=index">
    <div #origin style="opacity:0" >{{item}}</div>
    <div #copy  style="position:absolute" [style.z-index]="i" >{{item}}</div>
  </ng-container>
</div>
 @ViewChildren("origin") bars: QueryList<ElementRef>;
 @ViewChildren("copy") copies: QueryList<ElementRef>;

  ngAfterViewInit()
  {
    const bars:any[]=this.bars.toArray().map(x=>x.nativeElement.getBoundingClientRect());
    this.copies.forEach((x,index) => {
      x.nativeElement.style.top=bars[index].top+"px"
      x.nativeElement.style.left=bars[index].left+"px"
    });
  }
  click() {
    this.data=this.data
               .map(x=>({item:x,value:Math.random()}))
               .sort((a,b)=>a.value-b.value)
               .map(x=>x.item)

    setTimeout(()=>{
        const bars:any[]=this.bars.toArray().map 
           (x=>x.nativeElement.getBoundingClientRect());
        this.copies.forEach((x,index) => {
           this.animate(x.nativeElement, bars[index].top+"px",bars[index].left+"px");
        });
    })
  }
  animate(element: any, top: string,left:string) {
    const myAnimation = this.builder.build([
      animate(this.timing, style({ top: top,left:left }))
    ]);
    this.player = myAnimation.create(element);
    this.player.play();
  }
@Directive({ selector: "[animate]" })
export class AnimateDirective implements OnInit {
  original: any;
  copy: any;
  timing:string;
  private player: AnimationPlayer;

  @Input() set animate(value: string) {
    this.timing = value || "450ms ease-in-out";
  }
  @Input('animatePos0') pos0:boolean=false;

  constructor(
    private templateRef: TemplateRef<any>,
    private viewContainer: ViewContainerRef,
    private builder: AnimationBuilder,
    private renderer: Renderer2
  ) {}

  ngOnInit() {
    this.original = this.viewContainer.createEmbeddedView(
      this.templateRef
    ).rootNodes[0];
    setTimeout(() => {
      this.copy = this.viewContainer.createEmbeddedView(
        this.templateRef
      ).rootNodes[0];
      this.renderer.setStyle(this.original, "visibility","hidden");
      const rect = !this.pos0?
          {top:this.original.offsetTop,left:this.original.offsetLeft}:
          {top:0,left:0};
      this.renderer.setStyle(this.copy, "position", "absolute");
      this.renderer.setStyle(this.copy, "top", rect.top+ window.scrollY + "px");
      this.renderer.setStyle(this.copy, "left", rect.left+ window.scrollX + "px");
    });
  }
  animateGo() {
    setTimeout(() => {
      const rect = {top:this.original.offsetTop,left:this.original.offsetLeft}
      const myAnimation = this.builder.build([
        animate(this.timing, 
          style({ top: rect.top+ window.scrollY, 
                  left: rect.left+ window.scrollX }))
      ]);
      this.player = myAnimation.create(this.copy);
      this.player.play();
    });
  }
}
<ng-container *ngFor="let item of data;let i=index">
<div *animate="'150ms ease-in-out'"> {{item}}-{{i}}
</div>
</ng-container>
@ViewChildren(AnimateDirective) items:QueryList<AnimateDirective>
this.items.forEach(x=>x.animateGo())