Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
184 changes: 52 additions & 132 deletions src/guide/transitions-state.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,104 +52,27 @@ Vue.createApp(Demo).mount('#animated-number-demo')
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

When you update the number, the change is animated below the input. This makes for a nice demo, but what about something that isn't directly stored as a number, like any valid CSS color for example? Here's how we could accomplish this with [Tween.js](https://github.com/tweenjs/tween.js) and [Color.js](https://github.com/brehaut/color-js):

```html
<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>
```

```js
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 = ''
}
}
})
```

```css
.example-7-color-preview {
display: inline-block;
width: 50px;
height: 50px;
}
```

TODO: put in example
When you update the number, the change is animated below the input.

## Dynamic State Transitions

As with Vue's transition components, the data backing state transitions can be updated in real time, which is especially useful for prototyping! Even using a simple SVG polygon, you can achieve many effects that would be difficult to conceive of until you've played with the variables a little.

TODO: put in example

See [this example](https://codesandbox.io/s/github/vuejs/vuejs.org/tree/master/src/v2/examples/vue-20-dynamic-state-transitions) for the complete code behind the above demo.
<p class="codepen" data-height="500" data-theme-id="39028" data-default-tab="js,result" data-user="Vue" data-slug-hash="a8e00648d4df6baa1b19fb6c31c8d17e" data-preview="true" style="height: 493px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Updating SVG">
<span>See the Pen <a href="https://codepen.io/team/Vue/pen/a8e00648d4df6baa1b19fb6c31c8d17e">
Updating SVG</a> by Vue (<a href="https://codepen.io/Vue">@Vue</a>)
on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

## Organizing Transitions into Components

Managing many state transitions can quickly increase the complexity of a Vue instance or component. Fortunately, many animations can be extracted out into dedicated child components. Let's do this with the animated integer from our earlier example:

```html
<script src="https://cdn.jsdelivr.net/npm/tween.js@16.3.4"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.2.4/gsap.min.js"></script>

<div id="example-8">
<div id="app">
<input v-model.number="firstNumber" type="number" step="20" /> +
<input v-model.number="secondNumber" type="number" step="20" /> = {{ result }}
<p>
Expand All @@ -161,13 +84,22 @@ Managing many state transitions can quickly increase the complexity of a Vue ins
```

```js
// This complex tweening logic can now be reused between
// any integers we may wish to animate in our application.
// Components also offer a clean interface for configuring
// more dynamic transitions and complex transition
// strategies.
Vue.component('animated-integer', {
template: '<span>{{ tweeningValue }}</span>',
const app = Vue.createApp({
data() {
return {
firstNumber: 20,
secondNumber: 40
}
},
computed: {
result() {
return this.firstNumber + this.secondNumber
}
}
})

app.component('animated-integer', {
template: '<span>{{ fullValue }}</span>',
props: {
value: {
type: Number,
Expand All @@ -179,55 +111,43 @@ Vue.component('animated-integer', {
tweeningValue: 0
}
},
watch: {
value(newValue, oldValue) {
this.tween(oldValue, newValue)
computed: {
fullValue() {
return Math.floor(this.tweeningValue)
}
},
mounted() {
this.tween(0, this.value)
},
methods: {
tween(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()
}
}
})

// All complexity has now been removed from the main Vue instance!
new Vue({
el: '#example-8',
data() {
return {
firstNumber: 20,
secondNumber: 40
tween(newValue, oldValue) {
gsap.to(this.$data, {
duration: 0.5,
tweeningValue: newValue,
ease: 'sine'
})
}
},
computed: {
result() {
return this.firstNumber + this.secondNumber
watch: {
value(newValue, oldValue) {
this.tween(newValue, oldValue)
}
},
mounted() {
this.tween(this.value, 0)
}
})

app.mount('#app')
```

TODO: put in example
<p class="codepen" data-height="300" data-theme-id="39028" data-default-tab="js,result" data-user="Vue" data-slug-hash="e9ef8ac7e32e0d0337e03d20949b4d17" data-preview="true" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="State Transition Components">
<span>See the Pen <a href="https://codepen.io/team/Vue/pen/e9ef8ac7e32e0d0337e03d20949b4d17">
State Transition Components</a> by Vue (<a href="https://codepen.io/Vue">@Vue</a>)
on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

Now we can compose multiple states with these child components. It's exciting- we can use any combination of transition strategies that have been covered on this page, along with those offered by Vue's [built-in transition system](transitions.html). Together, there are very few limits to what can be accomplished.

Within child components, we can use any combination of transition strategies that have been covered on this page, along with those offered by Vue's [built-in transition system](transitions.html). Together, there are very few limits to what can be accomplished.
You can see how we could use this for data visualization, for physics effects, for character animations and interactions, the sky's the limit.

## Bringing Designs to Life

Expand All @@ -237,5 +157,5 @@ Vue can help. Since SVGs are just data, we only need examples of what these crea

Sarah Drasner demonstrates this in the demo below, using a combination of timed and interactivity-driven state changes:

<p data-height="265" data-theme-id="light" data-slug-hash="YZBGNp" data-default-tab="result" data-user="sdras" data-embed-version="2" data-pen-title="Vue-controlled Wall-E" class="codepen">See the Pen <a href="https://codepen.io/sdras/pen/YZBGNp/">Vue-controlled Wall-E</a> by Sarah Drasner (<a href="https://codepen.io/sdras">@sdras</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<p data-height="400" data-theme-id="light" data-slug-hash="YZBGNp" data-default-tab="result" data-user="sdras" data-embed-version="2" data-pen-title="Vue-controlled Wall-E" class="codepen">See the Pen <a href="https://codepen.io/sdras/pen/YZBGNp/">Vue-controlled Wall-E</a> by Sarah Drasner (<a href="https://codepen.io/sdras">@sdras</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>