状态间的过渡

Vue 的过渡系统提供了很多简便方法,可以在进入、离开时,以及对列表进行动画,但是对于数据变化的动画要如何处理呢?比如:

所有以上这些要么是存储为原始数字,要么可以转化为数字。一旦我们实现这步,就可以结合 Vue 的响应式和组件系统,使用第三方库补充中间状态(tween state),以对这些状态变化进行动画。

使用 watcher 对状态进行动画(Animating State with Watchers)

watcher 可以观察到从任何数值属性到另一个属性的变化,然后进行动画。这一抽象听起来很复杂,所以让我们深入一个使用 Tween.js 的例子:

<script src="https://cdn.jsdelivr.net/npm/tween.js@16.3.4"></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,
animatedNumber: 0
},
watch: {
number: function(newValue, oldValue) {
var vm = this
function animate () {
if (TWEEN.update()) {
requestAnimationFrame(animate)
}
}
new TWEEN.Tween({ tweeningNumber: oldValue })
.easing(TWEEN.Easing.Quadratic.Out)
.to({ tweeningNumber: newValue }, 500)
.onUpdate(function () {
vm.animatedNumber = this.tweeningNumber.toFixed(0)
})
.start()
animate()
}
}
})

{{ animatedNumber }}

当更新数值时,输入框下方就会对数值的更改进行动画。这是一个不错的 demo 示例,但是,对于不能直接存储为数字的值,比如有效的 CSS 颜色值?以下是我们如何通过添加 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="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;
}

Preview:

{{ tweenedCSSColor }}

动态状态过渡(Dynamic State Transitions)

就像 Vue 的过渡组件那样,动态数据所支撑的状态的过渡也可以实时更新,这对于制作原型十分有用!即使是一个简单的 SVG 多边形,在操作一些变量之后,也可是实现很多难以想象的效果。

See this fiddle for the complete code behind the above demo.

通过组件组织过渡(Organizing Transitions into Components)

管理太多的状态过渡,会快速增加 Vue 实例或者组件的复杂性。幸运的是,许多动画可以提取到专用的子组件中。让我们用前面的整数动画来举例:

<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
}
}
})
+ = {{ result }}

+ =

在子组件中,我们可以使用本页面所涵盖的所有过渡策略进行组合,再通过 Vue 提供的内置过渡系统 。将这些结合在一起,对于要实现的动画效果的限制很少。

赋予设计以生命

通过定义动画,可以给我们的设计带来生命。不幸的是,当设计师创建图标、logo 和吉祥物的时候,他们通常交付的都是图片或静态 SVG。所以,虽然 GitHub 章鱼猫、Twitter 小鸟以及其它许多 logo 都类似于生灵,它们看上去缺乏生气。

Vue 可以提供帮助。由于 SVG 的本质是数据,我们只需要提供这些动物活跃、思考或惊恐状态下的图例。然后 Vue 通过使用这些图例,来实现这几种状态之间的过渡动画,以制作欢迎页面、加载指示、以及触发情感的提示信息。

Sarah Drasner 提供了如下示例,通过把时间和交互组合,来驱动状态改变:

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


原文:https://vuejs.org/v2/guide/transitioning-state.html