状态过渡
Vue 除了可以对元素或组件提供进入、离开和列表的动效. 还可以将数值结合 Vue 的响应式和组件系统, 使用第三方库来实现切换元素的过渡状态
动态动画与侦听器
我们可以通过侦听器监听到数值属性的数值更新, 当数值更新时, 就会触发动画
1 2 3 4 5 6
| <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>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| 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 }) } } })
|
对于不能直接像数字一样存储的值,比如 CSS 中的 color 的值,通过下面的例子我们来通过 Tween.js 和 Color.js 实现一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <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>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| 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 = '' } } })
|
1 2 3 4 5
| .example-7-color-preview { display: inline-block; width: 50px; height: 50px; }
|
动态状态过渡
管理太多的状态过渡会很快的增加 Vue 实例或者组件的复杂性,幸好很多的动画可以提取到专用的子组件。
我们来将之前的示例改写一下:
1 2 3 4 5 6 7 8 9 10 11
| <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>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
|
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() } } })
new Vue({ el: '#example-8', data: { firstNumber: 20, secondNumber: 40 }, computed: { result: function() { return this.firstNumber + this.secondNumber } } })
|