Vue.js - это простой в использовании фреймворк для веб-приложений, который мы можем использовать для разработки интерактивных интерфейсных приложений.

В этой статье мы рассмотрим, как создавать переходы между состояниями с помощью GreenSock, tween.js и Color.js.

Анимация состояния с помощью наблюдателей

Наблюдатели позволяют анимировать изменения любого числового свойства в другое свойство.

Например, мы можем анимировать изменения числа, которое мы вводим с помощью GreenSock и Vue, следующим образом:

src/index.js :

new Vue({
  el: "#app",
  data: {
    num: 0,
    tweenedNumber: 0
  },
  computed: {
    animatedNumber() {
      return this.tweenedNumber.toFixed(0);
    }
  },
  watch: {
    num(newValue) {
      TweenLite.to(this.$data, 0.5, { tweenedNumber: newValue });
    }
  }
});

index.html :

<!DOCTYPE html>
<html>
  <head>
    <title>App</title>
    <meta charset="UTF-8" />
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.20.3/TweenMax.min.js"></script>
  </head>
  <body>
    <div id="app">
      <input v-model.number="num" type="number" />
      <p>{{ animatedNumber }}</p>
    </div>
    <script src="src/index.js"></script>
  </body>
</html>

Приведенный выше код будет анимировать изменения числа, когда мы вводим число во входные данные.

Мы смотрим значение num, а затем вызываем:

TweenLite.to(this.$data, 0.5, { tweenedNumber: newValue });

чтобы обновить отображение числа, увеличивая или уменьшая число, пока оно не достигнет числа, которое мы ввели.

TweenLite от GreenSock.

Мы также можем сделать то же самое для других вещей, таких как цветная строка.

Например, мы можем написать следующее, чтобы оживить обновление цветовой строки:

src/index.js :

const Color = net.brehaut.Color;
new Vue({
  el: "#app",
  data: {
    colorQuery: "",
    color: {
      red: 0,
      green: 0,
      blue: 0,
      alpha: 1
    },
    tweenedColor: {}
  },
  created() {
    this.tweenedColor = Object.assign({}, this.color);
  },
  watch: {
    color() {
      const animate = () => {
        if (TWEEN.update()) {
          requestAnimationFrame(animate);
        }
      };
new TWEEN.Tween(this.tweenedColor).to(this.color, 750).start();
animate();
    }
  },
  computed: {
    tweenedCSSColor() {
      return new Color({
        red: this.tweenedColor.red,
        green: this.tweenedColor.green,
        blue: this.tweenedColor.blue,
        alpha: this.tweenedColor.alpha
      }).toCSS();
    }
  },
  methods: {
    updateColor() {
      this.color = new Color(this.colorQuery).toRGB();
      this.colorQuery = "";
    }
  }
});

src/styles.css :

.color-preview {
  width: 50px;
  height: 50px;
}

index.js :

<!DOCTYPE html>
<html>
  <head>
    <title>App</title>
    <meta charset="UTF-8" />
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
    <link href="./src/styles.css" type="text/css" />
  </head>
  <body>
    <div id="app">
      <input
        v-model="colorQuery"
        @keyup.enter="updateColor"
        placeholder="Enter Color"
      />
      <button @click="updateColor">Update</button>
      <div
        class="color-preview"
        :style="{ backgroundColor: tweenedCSSColor }"
      ></div>
      <p>{{ tweenedCSSColor }}</p>
    </div>
    <script src="src/index.js"></script>
  </body>
</html>

Приведенный выше код работает, получая введенную строку colorQuery, преобразовывая ее в объект Color и присваивая ее this.color.

После обновления this.color будет вызвана функция animate в наблюдателе color в свойстве watch.

Затем this.tweenedColor будет обновлен:

new TWEEN.Tween(this.tweenedColor).to(this.color, 750).start();

Затем, когда this.tweenedColor обновляется, затем tweenedCSSColor обновляется и отображается на экране.

TWEEN.Tween - это конструктор из tween.js.

Организация переходов по компонентам

Мы можем поместить наш код перехода в его компонент. Таким образом, мы можем повторно использовать его и отделить сложность переходов от другой бизнес-логики.

Например, мы можем преобразовать наш исходный пример в следующий код:

src/index.js :

Vue.component("num-transition", {
  props: ["num"],
  data() {
    return {
      tweenedNumber: 0
    };
  },
  computed: {
    animatedNumber() {
      return this.tweenedNumber.toFixed(0);
    }
  },
  watch: {
    num(newValue) {
      TweenLite.to(this.$data, 0.5, { tweenedNumber: newValue });
    }
  },
  template: `<p>{{animatedNumber}}</p>`
});
new Vue({
  el: "#app",
  data: {
    num: 0
  }
});

index.html :

<!DOCTYPE html>
<html>
  <head>
    <title>App</title>
    <meta charset="UTF-8" />
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.20.3/TweenMax.min.js"></script>
  </head>
  <body>
    <div id="app">
      <input v-model.number="num" type="number" />
      <num-transition :num="num"></num-transition>
    </div>
    <script src="src/index.js"></script>
  </body>
</html>

В приведенном выше коде мы переместили логику перехода в отдельный компонент, убрав всю логику перехода и затем передав число, которое мы хотим наблюдать для создания перехода в качестве опоры.

Затем мы можем немного изменить его, чтобы мы могли повторно использовать его следующим образом:

src/index.js :

Vue.component("num-transition", {
  props: ["num"],
  data() {
    return {
      tweenedNumber: 0
    };
  },
  computed: {
    animatedNumber() {
      return this.tweenedNumber.toFixed(0);
    }
  },
  watch: {
    num(newValue) {
      TweenLite.to(this.$data, 0.5, { tweenedNumber: newValue });
    }
  },
  template: `<span>{{animatedNumber}}</span>`
});
new Vue({
  el: "#app",
  data: {
    num1: 0,
    num2: 0
  },
  computed: {
    result() {
      return this.num1 + this.num2;
    }
  }
});

index.html :

<!DOCTYPE html>
<html>
  <head>
    <title>App</title>
    <meta charset="UTF-8" />
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.20.3/TweenMax.min.js"></script>
  </head>
  <body>
    <div id="app">
      <input v-model.number="num1" type="number" />
      <input v-model.number="num2" type="number" />
      <p>
        <num-transition :num="num1"></num-transition> +
        <num-transition :num="num2"></num-transition> =
        <num-transition :num="result"></num-transition>
      </p>
    </div>
    <script src="src/index.js"></script>
  </body>
</html>

В приведенном выше коде мы изменили шаблон num-transition на:

<span>{{animatedNumber}}</span>

а затем в index.html мы изменили код на:

<div id="app">
  <input v-model.number="num1" type="number" />
  <input v-model.number="num2" type="number" />
  <p>
    <num-transition :num="num1"></num-transition> +
    <num-transition :num="num2"></num-transition> =
    <num-transition :num="result"></num-transition>
  </p>
</div>

Тогда получаем:

Заключение

Мы можем создавать переходы для состояний компонентов, наблюдая за ними и создавая для них вычисленные значения.

Затем мы можем использовать библиотеку GreenSock для генерации новых значений из наблюдаемого значения.

Затем это значение можно отобразить на экране, создав эффект анимации.

Мы можем преобразовать логику в отдельный компонент, чтобы она не делала компонент слишком сложным, смешивая логику перехода и другую бизнес-логику.