MaYaN
MaYaN

Reputation: 6996

How can I bind the animation duration in Vue.js?

What I am trying to build (and not use an existing solution) is an indeterminate loader with the following template:

<template>
  <div class="slider">
    <div class="line" :style="getLineStyle"></div>
    <div class="subline inc"></div>
    <div class="subline dec"></div>
  </div>
</template>

I then use a getter to add the styles for the div with the line class (which works fine).

  @Prop({ default: "hsl(0, 0%, 90%)" }) private backColor!: string;
  ...
  public get getLineStyle(): any {
    return {
      "background-color": "black",
      position: "absolute",
      opacity: "0.4",
      background: this.backColor,
      width: "150%",
      height: "100%"
    };
  }

I also have the following CSS:

<style lang="scss" scoped>
.slider {
  position: relative;
  height: 2px;
  overflow-x: hidden;
}

.subline {
  position: absolute;
  background: #4a8df8;
  height: 100%;
}

.inc {
  animation: increase 2s infinite;
}

.dec {
  animation: decrease 2s 0.5s infinite;
}

@keyframes increase {
  from {
    left: -5%;
    width: 5%;
  }
  to {
    left: 130%;
    width: 100%;
  }
}
@keyframes decrease {
  from {
    left: -80%;
    width: 80%;
  }
  to {
    left: 110%;
    width: 10%;
  }
}
</style>

What I want to do is turn the .inc and .dec classes to property getters as well so that I can bind the animation duration (currently set to 2s) to a property.

I initially tried modifying the template to:

<template>
  <div class="slider">
    <div class="line" :style="getLineStyle"></div>
    <div class="subline inc" :style="getAnimateIncreaseStyle"></div>
    <div class="subline dec" :style="getAnimateDecreaseStyle"></div>
  </div>
</template>

With the following getters:

  public get getAnimateIncreaseStyle() {
    return {
      animation: "increase 2s infinite"
    };
  }

  public get getAnimateDecreaseStyle() {
    return {
      animation: "decrease 2s 0.5s infinite"
    };
  }

Only to realise that animations cannot work when added inline.

I cannot think of any other way of doing this. Any ideas?

Upvotes: 2

Views: 2277

Answers (1)

PaKo Anguiano
PaKo Anguiano

Reputation: 141

This is how i bind the animation duration on my progress bar in vue 3, as the previous response. It's necessary removes the scope on style

<template>
...
  <div v-if="duration > 0" class="w-full bg-gray-200 -mb-1">
    <div
      :class="`progress-bar h-0.5 progress-bar-${themeColor}`"
      :style="animation"
    ></div>
  </div>
...
</template>

<script lang="ts">
    ...
    props: {
        duration: {
            type: Number,
            default: 10,
        },
        themeColor: {
           type: String,
           required: false,
           default: "blue",
        },
    },
    computed: {
        animation(): string {
          return `animation: ${this.duration}s linear theme-color, ${this.duration}s ease-out enter forwards`;
        },
    },
    ...
<script>

<style lang="scss">
.progress-bar {
  @apply bg-gray-300;
  transform-origin: right;

  &.progress-bar-blue {
    @apply bg-gradient-to-r from-blue-600 to-blue-300;
  }

  &.progress-bar-green {
    @apply bg-gradient-to-r from-green-600 to-green-300;
  }

  &.progress-bar-yellow {
    @apply bg-gradient-to-r from-yellow-600 to-yellow-300;
  }

  &.progress-bar-red {
    @apply bg-gradient-to-r from-red-500 to-red-300;
  }
}

@keyframes theme-color {
  100% {
    background-position: 0%;
  }
  0% {
    background-position: 100%;
  }
}

@keyframes enter {
  100% {
    transform: scaleX(0);
  }
  0% {
    transform: scaleX(1);
  }
}
</style>

Upvotes: 1

Related Questions