Vue动画
Vue动画
使用过度类名实现动画
-
将要使用过度动画的标签用transition包裹
-
定义两组样式
<!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../js/vue.js"></script> <style> /*v-enter是进入之前元素的样式,此时动画还没开始*/ /*v-leave-to是动画离开之后离开的终止样式,此时动画已经结束*/ .v-enter, .v-leave-to { opacity: 0; /* transform: translateX(150px); */ transform: translate3d(100px, 10px, 100px); } /*v-enter-active【入场动画的时间段】*/ /*v-leave-active【离场动画的时间段】*/ .v-enter-active, .v-leave-active { transition: all 0.6s ease; } </style> </head> <body> <div id="app"> <!-- 点击按钮显示h3 --> <!-- 1.使用transition元素将需要被动画控制的元素包裹起来,transition是vue提供的 --> <!-- 2. 自定义两组样式来自定义transition内的元素 --> <button @click="flag=!flag">toggle</button> <transition> <!--只能包裹一个标签--> <h3 v-if="flag">这是一个h3</h3> </transition> </div> <script> var vm = new Vue({ el: '#app', data: { flag: false }, methods: {} }); </script> </body> </html>
自定义样式前缀
- 可以在transition标签中用name来指定对应的样式前缀
<transition name="my">
<!--只能包裹一个标签-->
<h3 v-if="flag">这是一个h3</h3>
</transition>
- 这样做的话,在定义动画时也要用my作为前缀
<style>
.my-enter,
.my-leave-to {
opacity: 0;
transform: translate3d(100px, 10px, 100px);
}
.my-enter-active,
.my-leave-active {
transition: all 0.6s ease;
}
</style>
使用第三方类库实现动画----Animate.css
在transition上用enter-active-class="动画类"指定进入动画用leave-active-class="动画类"指定离开类
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="../css/animate.min.css">
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<button @click="flag=!flag">toggle</button>
<transition enter-active-class="animate__bounceIn" leave-active-class="animate__bounceOut">
<h3 v-if="flag">这是一个h3</h3>
</transition>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
flag: false
},
methods: {}
});
</script>
</body>
</html>
JavaScript 钩子
可以在 attribute 中声明 JavaScript 钩子
<transition
v-on:before-enter="beforeEnter"
v-on:enter="enter"
v-on:after-enter="afterEnter"
v-on:enter-cancelled="enterCancelled"
v-on:before-leave="beforeLeave"
v-on:leave="leave"
v-on:after-leave="afterLeave"
v-on:leave-cancelled="leaveCancelled"
>
<!-- ... -->
</transition>
// ...
methods: {
// --------
// 进入中
// --------
beforeEnter: function (el) {
// ...
},
// 当与 CSS 结合使用时
// 回调函数 done 是可选的
enter: function (el, done) {
// ...
done()
},
afterEnter: function (el) {
// ...
},
enterCancelled: function (el) {
// ...
},
// --------
// 离开时
// --------
beforeLeave: function (el) {
// ...
},
// 当与 CSS 结合使用时
// 回调函数 done 是可选的
leave: function (el, done) {
// ...
done()
},
afterLeave: function (el) {
// ...
},
// leaveCancelled 只用于 v-show 中
leaveCancelled: function (el) {
// ...
}
}
这些钩子函数可以结合 CSS transitions/animations
使用,也可以单独使用。
当只用 JavaScript 过渡的时候,在
enter
和leave
中必须使用done
进行回调。否则,它们将被同步调用,过渡会立即完成。
推荐对于仅使用 JavaScript 过渡的元素添加
v-bind:css="false"
,Vue 会跳过 CSS 的检测。这也可以避免过渡过程中 CSS 的影响。
一个使用 Velocity.js 的简单例子:
<!--
Velocity 和 jQuery.animate 的工作方式类似,也是用来实现 JavaScript 动画的一个很棒的选择
-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script>
<div id="example-4">
<button @click="show = !show">
Toggle
</button>
<transition
v-on:before-enter="beforeEnter"
v-on:enter="enter"
v-on:leave="leave"
v-bind:css="false"
>
<p v-if="show">
Demo
</p>
</transition>
</div>
new Vue({
el: '#example-4',
data: {
show: false
},
methods: {
beforeEnter: function (el) {
el.style.opacity = 0
el.style.transformOrigin = 'left'
},
enter: function (el, done) {
Velocity(el, { opacity: 1, fontSize: '1.4em' }, { duration: 300 })
Velocity(el, { fontSize: '1em' }, { complete: done })
},
leave: function (el, done) {
Velocity(el, { translateX: '15px', rotateZ: '50deg' }, { duration: 600 })
Velocity(el, { rotateZ: '100deg' }, { loop: 2 })
Velocity(el, {
rotateZ: '45deg',
translateY: '30px',
translateX: '30px',
opacity: 0
}, { complete: done })
}
}
})
多个元素的过渡
我们之后讨论多个组件的过渡,对于原生标签可以使用 v-if
/v-else
。最常见的多标签过渡是一个列表和描述这个列表为空消息的元素:
<transition>
<table v-if="items.length > 0">
<!-- ... -->
</table>
<p v-else>Sorry, no items found.</p>
</transition>
可以这样使用,但是有一点需要注意:
当有相同标签名的元素切换时,需要通过
key
attribute 设置唯一的值来标记以让 Vue 区分它们,否则 Vue 为了效率只会替换相同标签内部的内容。即使在技术上没有必要,给在 `` 组件中的多个元素设置 key 是一个更好的实践。
示例:
<transition>
<button v-if="isEditing" key="save">
Save
</button>
<button v-else key="edit">
Edit
</button>
</transition>
在一些场景中,也可以通过给同一个元素的 key
attribute 设置不同的状态来代替 v-if
和 v-else
,上面的例子可以重写为:
<transition>
<button v-bind:key="isEditing">
{{ isEditing ? 'Save' : 'Edit' }}
</button>
</transition>
使用多个 v-if
的多个元素的过渡可以重写为绑定了动态 property 的单个元素过渡。例如:
<transition>
<button v-if="docState === 'saved'" key="saved">
Edit
</button>
<button v-if="docState === 'edited'" key="edited">
Save
</button>
<button v-if="docState === 'editing'" key="editing">
Cancel
</button>
</transition>
可以重写为:
<transition>
<button v-bind:key="docState">
{{ buttonMessage }}
</button>
</transition>
// ...
computed: {
buttonMessage: function () {
switch (this.docState) {
case 'saved': return 'Edit'
case 'edited': return 'Save'
case 'editing': return 'Cancel'
}
}
}