无法使用 Angular 动画正确设置轮播

Not able to set Carousel properly using Angular Animations

我使用 Angular 动画创建了以下旋转木马:

我创建了 5 个定义每个状态位置的变量:

但是当我尝试添加更多数据时,有些项目只是从动画中消失(如上图中的 'Joe' 和 'Hidde')。

我正在努力实现以下目标:

(i) 如果数据更多,我需要继续播放动画(不知从何处进入右侧的 DOM,我想我们可以使用 ':enter' 和 ':leave 做到这一点' 别名但不能在这里应用它们。)

(ii) 假设只有两个项目,那么项目应该在 'current' 和 'next' 状态之间进行动画处理,但不会移动到最右边。

这里是 Stackblitz link

这是代码:

.ts:

animations: [
    trigger("carousel", [
      state(
        "current",
        style({
          position: "absolute",
          top: "16%",
          right: "54%",
          bottom: "39%",
          left: "40%"
        })
      ),
      state(
        "next",
        style({
          position: "absolute",
          top: "51%",
          right: "77%",
          bottom: "calc(2% + 3px)",
          left: "calc(1% + 6px)"
        })
      ),
      state(
        "futureNext",
        style({
          position: "absolute",
          top: "51%",
          right: "54%",
          bottom: "calc(2% + 3px)",
          left: "calc(26% + 5px)"
        })
      ),
      state(
        "postFutureNext",
        style({
          position: "absolute",
          top: "51%",
          right: "31%",
          bottom: "calc(2% + 3px)",
          left: "calc(51% + 5px)"
        })
      ),
      state(
        "nextToPostFutureNext",
        style({
          position: "absolute",
          top: "51%",
          right: "8%",
          bottom: "calc(2% + 3px)",
          left: "calc(76% + 4px)"
        })
      ),
      transition(
        "current <=> nextToPostFutureNext",
        animate("2000ms ease-in-out")
      ),
      transition(
        "nextToPostFutureNext <=> postFutureNext",
        animate("2000ms ease-in-out")
      ),
      transition(
        "postFutureNext <=> futureNext",
        animate("2000ms ease-in-out")
      ),
      transition("futureNext <=> next", animate("2000ms ease-in-out")),
      transition("next <=> current", animate("2000ms ease-in-out"))
    ])
  ]
    clearTimeOutVar: any;
      current = 0;
      next = 1;
      futureNext = 2;
      postFutureNext = 3;
      nextToPostFutureNext = 4;

  ngOnInit() {
    this.runSlideShow();
  }

  runSlideShow() {
    this.clearTimeOutVar = setTimeout(() => {
      this.updateAnimationVariables();
      this.runSlideShow();
    }, 3000);
  }

  updateAnimationVariables() {
    if (this.current === 4) {
      this.current = 0;
    } else if (this.current < 4) {
      this.current++;
    }

    if (this.next === 4) {
      this.next = 0;
    } else if (this.next < 4) {
      this.next++;
    }

    if (this.futureNext === 4) {
      this.futureNext = 0;
    } else if (this.futureNext < 4) {
      this.futureNext++;
    }

    if (this.postFutureNext === 4) {
      this.postFutureNext = 0;
    } else if (this.postFutureNext < 4) {
      this.postFutureNext++;
    }

    if (this.nextToPostFutureNext === 4) {
      this.nextToPostFutureNext = 0;
    } else if (this.nextToPostFutureNext < 4) {
      this.nextToPostFutureNext++;
    }
  }

  ngOnDestroy() {
    clearTimeout(this.clearTimeOutVar);
  }

.html:

<div class="container">
    <div class="header">
        A Simple Carousel
    </div>
    <div class="data">
        <div class="cards" *ngFor="let item of data; let i = index;" [@carousel]="
        i == current ? 'current' :
        i == next ? 'next' : 
        i == futureNext ? 'futureNext' : 
        i == postFutureNext ? 'postFutureNext' : 
        i == nextToPostFutureNext ? 'nextToPostFutureNext' : ''
      ">
            <div class="name">{{ item.name }}</div>
            <div class="age">{{ item.age }}</div>
        </div>
    </div>
</div>

如果我无法解释我的方法中的任何一点,请告诉我。

谢谢。

我很难想象你想做什么样的动画。顺便说一句(我希望不要混淆你),你只能通过代码创建动画。有些人喜欢

想法是在构造函数中注入动画构建器

  constructor(private builder: AnimationBuilder) {}

在它总是相同之后,我们使用 ViewChildren 和其他使用 ViewChild 的元素来制作动画

  @ViewChildren("card") items: QueryList<ElementRef>;
  @ViewChild("container") container: ElementRef;
  @ViewChild("dataInit") dataInit: ElementRef;

我们创建了一个函数来计算辅助变量,使我们能够计算项目的最终位置

  calculateDimensions() {
    this.rectElement = this.items.first.nativeElement.getBoundingClientRect();
    const rect = this.dataInit.nativeElement.getBoundingClientRect();
    const rectContainer = this.container.nativeElement.getBoundingClientRect();

    this.rect = {};
    this.rect.height = rectContainer.height - rect.y;
    this.rect.y = rect.y;
    this.rect.width = rectContainer.width - this.rectElement.width;
  }

并且在 ngAfterViewInit 中调用这个函数和一个动画函数

  ngAfterViewInit() {
    this.calculateDimensions();
    this.animateCarousel();
  }

让我们使用函数 animateCarousel

  animateCarousel() {
    //with each element in ViewChildren
    this.items.forEach((item: ElementRef, index: number) => {

      //I calcule the "order" to change the z-index of the element
      this.order[index] =this.items.length-
        ((index + this.selectedIndex) % this.items.length);

      //Calcule the style final
      const itemStyle = this.getStyle2(index);

      //create an animation using this.builder.build
      const myAnimation = this.builder.build([
        animate(this.timing, style(itemStyle))
      ]);

      //Use a variable "player" declared: private player: AnimationPlayer;
      //and the animation.create over the "nativeElement"
      this.player = myAnimation.create(item.nativeElement);

      //As we want an infinite carousel, with one element (I choose the first)
      if (index == 0)
        //when finish, 
        this.player.onDone(() => {
          this.calculateDimensions(); //recalcule the dimensions
                                      //this makes that if resize the navigator
                                      //the animation works well
                  
          //add or substract the "selectedIndex" using % operator
          //to always gets values from 0 to this.items.length-1
          this.selectedIndex =
            (this.selectedIndex + this.items.length - 1) % this.items.length;

          //and call to the function again
          this.animateCarousel();
        });

       //Finally say player.play()
      this.player.play();
    });
  }

嗯,函数 getStyles 可以是我们想要的,但总有办法

  getStyle(index: number) {
    //get the "pos" that it's always
    const pos = (index + this.selectedIndex) % this.items.length;

    //now we return the style we want, e.g.
    if (pos == 0)
      return { top: this.rect.y + "px", left: this.rect.width / 2 + "px" };

    return {
      top: this.rect.height - this.rectElement.height / 2 + "px",
      left: pos * (this.rect.width / this.items.length) + "px"
    };
  }

.html

<div #container class="container">

    <div class="header">
        A Simple Carousel
    </div>
    <!--this div it's only to situate the carousel-->
    <div #dataInit class="data"></div>

    <!--see how change the "z-index"
    <div #card class="cards" [ngStyle]="{'z-index':order[i]}" 
       *ngFor="let item of data; let i = index;">
            <div class="name">{{ item.name }}</div>
            <div class="age">{{ item.age }}</div>
    </div>
</div>

可以看到the final result