【问题标题】:Not able to set Carousel properly using Angular Animations无法使用 Angular Animations 正确设置 Carousel
【发布时间】:2021-04-18 11:19:51
【问题描述】:

我使用 Angular Animations 创建了以下轮播:

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

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

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

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

(ii) 假设如果只有两个项目,那么项目应该在“当前”和“下一个”状态之间进行动画处理,但不会转到最右边。

这是 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>

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

谢谢。

【问题讨论】:

    标签: angular angular-animations


    【解决方案1】:

    我很难想象你想做什么样的动画。顺便说一句(我希望不要让您感到困惑),您只能通过代码创建动画。有些喜欢this SO

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

      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

    【讨论】:

    • 谢谢。我能够实现这一点,但需要你在另一个 thread 的帮助
    • 您好,Eliseo,面临新情况,不知道如何处理。这是thread。请帮忙。谢谢
    猜你喜欢
    • 2022-10-30
    • 2019-05-06
    • 1970-01-01
    • 2012-06-05
    • 2012-05-19
    • 2020-01-07
    • 1970-01-01
    • 1970-01-01
    • 2015-05-29
    相关资源
    最近更新 更多