state transition


Directory


Vue's transition system provides many simple ways to animate entry, exit, and lists. What about the animation of the data element itself, such as:

  • Numbers and operations

  • Color display

  • The position of the SVG node

  • The size and other attributes of the element

These data are either stored in numerical form themselves, or Can be converted to a numeric value. With these values ​​in mind, we can combine Vue's responsiveness and component system and use a third-party library to implement the transition state of switching elements.


Status animation and listener


We can monitor through the listener Numeric update of any numeric property. Might sound abstract, so let's first look at an example using 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 });
    }
  }
})

20.gif

When you update the value, Animation will be triggered. This is a good demonstration, but for values ​​that cannot be stored directly like numbers, such as the value of color in CSS, through the following example we use Tween.js and Color.js Implement an example:

<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="Enter a color"
  >
  <button v-on:click="updateColor">Update</button>
  <p>Preview:</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;
}

1.gif


##Dynamic state transition


Just like Vue's transition component, the state transition behind the data will be updated in real time, which is very useful for prototyping. When you modify some variables, even a simple SVG polygon can achieve many unimaginable effects.


2.gif

The code behind the above demo can be read in detail through

this fiddle.


Put the transition in the component


It will be very difficult to manage too many state transitions Quickly increase the complexity of your Vue instance or component. Fortunately, many animations can be extracted into dedicated subcomponents.


Let’s rewrite the previous example:

<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>
// 这种复杂的补间动画逻辑可以被复用
// 任何整数都可以执行动画
// 组件化使我们的界面十分清晰
// 可以支持更多更复杂的动态过渡
// 策略。
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()
    }
  }
})
// 所有的复杂度都已经从 Vue 的主实例中移除!
new Vue({
  el: '#example-8',
  data: {
    firstNumber: 20,
    secondNumber: 40
  },
  computed: {
    result: function () {
      return this.firstNumber + this.secondNumber
    }
  }
})

3.gif

We can combine them in components. This section talks about various transition strategies and Vue Built-in transition system. In short, there are almost no obstacles to completing various transition effects.


Bringing design to life


Just one animation can bring life. Unfortunately, when designers create icons, logos, and mascots, they are often delivered as images or static SVGs. So, while GitHub’s octopus cat, Twitter’s bird, and many other logos resemble living beings, they don’t actually look alive.

Vue can help you. Since the nature of SVG is data, we only need examples of these animals being excited, thinking, or alert. Then Vue can assist in completing the transition animation between these states to create your welcome page, loading instructions, and more emotional prompts.

Sarah Drasner showed the following demo, which combines time and interaction-related state changes: