Transisi State

Terdapat banyak cara sederhana pada sistem transisi Vue untuk animasi masuk, keluar dan daftar, tetapi bagaimana dengan menganimasi data Anda sendiri? Sebagai contoh:

Semuanya ini bisa saja sudah disimpan sebagai angka mentah (raw number) atau belum dikonversi menjadi angka. Ketika kita melakukan hal itu, kita dapat menganimasi perubahan state ini menggunakan pustaka pihak ketiga menjadi tween state, dalam kombinasi dengan reaktivitas Vue dan sistem komponennya.

Menganimasi State Menggunakan Watcher

Dengan menggunakan watcher, kita dapat menganimasi perubahan dari properti numerik apapun menjadi properti lain. Hal tersebut terkesan rumit untuk dibayangkan, jadi mari kita pahami contoh berikut menggunakan GreenSock:

<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.20.3/TweenMax.min.js"></script>

<div id="animated-number-demo">
  <input v-model.number="number" type="number" step="20">
  <p>{{ animatedNumber }}</p>
</div>
new Vue({
  el: '#animated-number-demo',
  data: {
    number: 0,
    tweenedNumber: 0
  },
  computed: {
    animatedNumber: function() {
      return this.tweenedNumber.toFixed(0);
    }
  },
  watch: {
    number: function(newValue) {
      TweenLite.to(this.$data, 0.5, { tweenedNumber: newValue });
    }
  }
})

{{ animatedNumber }}

Ketika Anda mengubah angka, perubahannya dianimasi di bawah input. Ini demo yang baik, tetapi bagaimana dengan sesuatu yang tidak secara langsung disimpan sebagai angka, seperti warna valid CSS sebagai contoh? Berikut ini adalah bagaimana kita dapat menyelesaikannya menggunakan Tween.js dan Color.js:

<script src="https://cdn.jsdelivr.net/npm/tween.js@16.3.4"></script>
<script src="https://cdn.jsdelivr.net/npm/color-js@1.0.3"></script>

<div id="example-7">
  <input
    v-model="colorQuery"
    v-on:keyup.enter="updateColor"
    placeholder="Masukkan sebuah warna"
  >
  <button v-on:click="updateColor">Ubah</button>
  <p>Pratinjau:</p>
  <span
    v-bind:style="{ backgroundColor: tweenedCSSColor }"
    class="example-7-color-preview"
  ></span>
  <p>{{ tweenedCSSColor }}</p>
</div>
var Color = net.brehaut.Color

new Vue({
  el: '#example-7',
  data: {
    colorQuery: '',
    color: {
      red: 0,
      green: 0,
      blue: 0,
      alpha: 1
    },
    tweenedColor: {}
  },
  created: function () {
    this.tweenedColor = Object.assign({}, this.color)
  },
  watch: {
    color: function () {
      function animate () {
        if (TWEEN.update()) {
          requestAnimationFrame(animate)
        }
      }

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

      animate()
    }
  },
  computed: {
    tweenedCSSColor: function () {
      return new Color({
        red: this.tweenedColor.red,
        green: this.tweenedColor.green,
        blue: this.tweenedColor.blue,
        alpha: this.tweenedColor.alpha
      }).toCSS()
    }
  },
  methods: {
    updateColor: function () {
      this.color = new Color(this.colorQuery).toRGB()
      this.colorQuery = ''
    }
  }
})
.example-7-color-preview {
  display: inline-block;
  width: 50px;
  height: 50px;
}

Pratinjau:

{{ tweenedCSSColor }}

Transisi State Dinamis

Sebagaimana dengan transisi komponen Vue, data yang mendukung transisi state dapat diubah secara waktu nyata (real time), yang mana secara khusus berguna untuk membuat prototipe! Meskipun hanya menggunakan poligon SVG sederhana, Anda dapat memperoleh banyak efek yang sulit untuk dihasilkan sampai Anda sedikit bermain dengan variabel.

Lihat fiddle ini untuk kode selengkapnya dari demo di atas.

Mengatur Transisi dalam Komponen

Mengelola banyak transisi state dapat menambah kerumitan dari sebuah instance atau komponen Vue secara singkat. Beruntung, banyak animasi dapat dikeluarkan ke suatu anak komponen yang telah didedikasikan. Mari kita melakukannya dengan animasi integer dari contoh sebelumnya:

<script src="https://cdn.jsdelivr.net/npm/tween.js@16.3.4"></script>

<div id="example-8">
  <input v-model.number="firstNumber" type="number" step="20"> +
  <input v-model.number="secondNumber" type="number" step="20"> =
  {{ result }}
  <p>
    <animated-integer v-bind:value="firstNumber"></animated-integer> +
    <animated-integer v-bind:value="secondNumber"></animated-integer> =
    <animated-integer v-bind:value="result"></animated-integer>
  </p>
</div>
// Logika tweening yang rumit ini kini dapat digunakan kembali di antara
// integer apapun yang kita inginkan untuk dianimasikan dalam aplikasi kita.
// Komponen juga menawarkan sebuah antarmuka yang bersih untuk mengkonfigurasi
// lebih banyak strategi transisi dinamis dan transisi rumit
Vue.component('animated-integer', {
  template: '<span>{{ tweeningValue }}</span>',
  props: {
    value: {
      type: Number,
      required: true
    }
  },
  data: function () {
    return {
      tweeningValue: 0
    }
  },
  watch: {
    value: function (newValue, oldValue) {
      this.tween(oldValue, newValue)
    }
  },
  mounted: function () {
    this.tween(0, this.value)
  },
  methods: {
    tween: function (startValue, endValue) {
      var vm = this
      function animate () {
        if (TWEEN.update()) {
          requestAnimationFrame(animate)
        }
      }

      new TWEEN.Tween({ tweeningValue: startValue })
        .to({ tweeningValue: endValue }, 500)
        .onUpdate(function () {
          vm.tweeningValue = this.tweeningValue.toFixed(0)
        })
        .start()

      animate()
    }
  }
})

// Semua kerumitan telah dihilangkan dari instance utama Vue!
new Vue({
  el: '#example-8',
  data: {
    firstNumber: 20,
    secondNumber: 40
  },
  computed: {
    result: function () {
      return this.firstNumber + this.secondNumber
    }
  }
})
+ = {{ result }}

+ =

Dalam anak komponen, kita dapat menggunakan kombinasi strategi transisi apapun yang telah tercakup pada halaman ini, bersama dengan yang ditawarkan oleh sistem transisi built-in Vue. Dengan demikian, batasan menjadi minim dari apa yang bisa diperoleh.

Menghidupkan Desain

Menganimasi dapat didefinisikan sebagai memberi kehidupan. Sayang sekali, ketika desainer membuat ikon, logo, dan maskot, mereka biasanya menyerahkannya dalam bentuk gambar atau SVG statis. Jadi meskipun octocat Github, burung Twitter, dan banyak logo lain menyerupai makhluk hidup, mereka tidak terkesan sungguh-sungguh hidup.

Vue dapat membantu dalam hal ini. Karena SVG hanyalah data, kita cukup memerlukan contoh seperti apa makhluk-makhluk tersebut ketika gembira, berpikir, atau khawatir. Setelah itu, Vue dapat membantu transisi antar state-nya, membuat halaman selamat datang, memuat indikator-indikator, dan notifikasi menjadi lebih menarik secara emosional.

Sarah Drasner menunjukannya dalam demo di bawah ini, menggunakan sebuah kombinasi dari perubahan timed dan interactivity-driven state:

See the Pen Vue-controlled Wall-E by Sarah Drasner (@sdras) on CodePen.