单元素过渡
一、单元素过渡
Vue 在插入、更新或者移除 DOM 时,提供多种不同方式的应用过渡效果。
1.单元素/组件的过渡
Vue 提供了 transition 的封装组件,在下列情形中,可以给任何元素和组件添加进入/离开过渡
- 条件渲染 (使用 v-if)
- 条件展示 (使用 v-show)
- 动态组件
- 组件根节点
2.过渡的类名
在进入/离开的过渡中,会有 6 个 class 切换。
1. v-enter:
定义进入过渡的开始状态。
在元素被插入之前生效,在元素被插入之后的下一帧移除。
2. v-enter-active:
定义进入过渡生效时的状态。
在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。
这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。
3. v-enter-to:
定义进入过渡的结束状态(2.1.8+) 。
在元素被插入之后下一帧生效 (与此同时 v-enter 被移除),在过渡/动画完成之后移除。
4. v-leave:
定义离开过渡的开始状态。
在离开过渡被触发时立刻生效,下一帧被移除。
5. v-leave-active:
定义离开过渡生效时的状态。
在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。
这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。
5. v-leave-to:
定义离开过渡的结束状态(2.1.8+) 。
在离开过渡被触发之后下一帧生效 (与此同时 v-leave 被删除),在过渡/动画完成之后移除。
<template>
<div class="demo">
<button @click="show = !show">click</button>
<transition>
<div class="box" v-show="show">hellow world</div>
</transition>
</div>
</template>
<script>
export default {
data(){
return {
show: true
}
}
}
</script>
<style scoped>
button {
margin-bottom: 10px;
}
.box {
width: 100px;
height: 100px;
line-height: 100px;
text-align: center;
border: 1px solid red;
color: red;
}
.v-enter {
opacity: 0;
transform: translateX(250px);
}
.v-enter-active {
transition: all 0.8s;
}
.v-enter-to {
opacity: 1;
transform: translateX(0px);
}
.v-leave {
opacity: 1;
transform: translateX(0px);
}
.v-leave-active {
transition: all 0.8s;
}
.v-leave-to {
opacity: 0;
transform: translateX(250px);
}
</style>
3.类名前缀
- transition 无 name 特性
类名前缀为 v-。
.v-enter {
opacity: 0;
transform: translateX(250px);
}
.v-enter-active {
transition: all 0.8s;
}
.v-enter-to {
opacity: 1;
transform: translateX(0px);
}
.v-leave {
opacity: 1;
transform: translateX(0px);
}
.v-leave-active {
transition: all 0.8s;
}
.v-leave-to {
opacity: 0;
transform: translateX(250px);
}
- transition 有 name 特性
如 name 为 fade,则类名前缀为fade-。
<template>
<div class="demo">
<button @click="show = !show">click</button>
<transition name="box1">
<div class="box" v-if="show">hello world</div>
</transition>
<transition name="box2">
<div class="box" v-if="show">hello world</div>
</transition>
</div>
</template>
<script>
export default {
data () {
return {
show: true,
}
}
}
</script>
<style scoped>
button {
margin-bottom: 10px;
}
.box {
width: 100px;
height: 100px;
margin-bottom: 10px;
line-height: 100px;
text-align: center;
border: 1px solid red;
color: red;
}
/* 合并代码,减少耦合和代码量 */
.box1-enter,
.box1-leave-to {
opacity: 0;
transform: translateX(200px);
}
.box1-enter-active,
.box1-leave-active {
transition: all .3s;
}
.box1-enter-to,
.box1-leave {
opacity: 1;
transform: translateX(0px);
}
.box2-enter-to,
.box2-leave {
opacity: 1;
transform: translateY(0px);
}
.box2-enter-active,
.box2-leave-active {
transition: all .3s;
}
.box2-enter,
.box2-leave-to {
opacity: 0;
transform: translateY(200px);
}
</style>
4.CSS 动画
CSS 动画用法同 CSS 过渡,区别是在动画中 v-enter 类名在节点插入 DOM 后不会立即删除,而是在 animationend 事件触发时删除。
<template>
<div class="demo">
<button @click="show = !show">click</button>
<transition>
<div class="box" v-if="show">hello world</div>
</transition>
</div>
</template>
<script>
export default {
data () {
return {
show: true,
}
}
}
</script>
<style scoped>
button {
margin-bottom: 10px;
}
.box {
width: 100px;
height: 100px;
margin-bottom: 10px;
line-height: 100px;
text-align: center;
border: 1px solid red;
color: red;
}
.v-enter-active {
animation: animate 1s;
}
.v-leave-active {
animation: animate 1s reverse;
}
@keyframes animate {
0% {
opacity: 0;
transform: translateX(400px) scale(1);
}
50% {
opacity: .5;
transform: translateX(200px) scale(1.5);
}
100% {
opacity: 1;
transform: translateX(0) scale(1);
}
}
</style>
5.自定义过渡的类名
我们可以通过以下 attribute 来自定义过渡类名:
- enter-class
- enter-active-class
- enter-to-class (2.1.8+)
- leave-class
- leave-active-class
- leave-to-class (2.1.8+)
<template>
<div class="demo">
<button @click="show = !show">click</button>
<transition enter-active-class="enter" leave-active-class="leave">
<div class="box" v-if="show">hello world</div>
</transition>
</div>
</template>
<script>
export default {
data () {
return {
show: true,
}
}
}
</script>
<style scoped>
button {
margin-bottom: 10px;
}
.box {
width: 100px;
height: 100px;
margin-bottom: 10px;
line-height: 100px;
text-align: center;
border: 1px solid red;
color: red;
}
.enter {
animation: animate 1s;
}
.leave {
animation: animate 1s reverse;
}
@keyframes animate {
0% {
opacity: 0;
transform: translateX(400px) scale(1);
}
50% {
opacity: .5;
transform: translateX(200px) scale(1.5);
}
100% {
opacity: 1;
transform: translateX(0) scale(1);
}
}
</style>
他们的优先级高于普通的类名,这对于 Vue 的过渡系统和其他第三方 CSS 动画库(如 Animate.css)结合使用十分有用。
由于我们不会愿意花太多时间去写一个好的动画,那么通过命名就能对各样动画进行命名。
下面推荐一款动画的css
Animate.css 官网地址:https://daneden.github.io/animate.css/
安装方式:npm install animate.css --save
,最后引入css
<template>
<div class="demo">
<button @click="show = !show">click</button>
<transition
enter-active-class="animated bounceInRight"
leave-active-class="animated bounceOutDown">
<div class="box" v-if="show">hello world</div>
</transition>
</div>
</template>
6.同时使用过渡和动画
可使用 type 属性,来声明需要 Vue 监听的类型,type值可为 animation 或 transition 。
当不设置type时,默认会取 transitioned 和 animationed 两者更长的为结束时刻。(以哪个为主)
<template>
<div class="demo">
<button @click="show = !show">click</button>
<transition
type="animation"
enter-active-class="animated tada v-enter-active"
leave-active-class="animated tada v-leave-active"
>
<div class="box" v-if="show">hello world</div>
</transition>
</div>
</template>
<script>
export default {
data () {
return {
show: true,
}
}
}
</script>
<style scoped>
button {
margin-bottom: 10px;
}
.box {
width: 100px;
height: 100px;
margin-bottom: 10px;
line-height: 100px;
text-align: center;
border: 1px solid red;
color: red;
}
.v-enter,
.v-leave-to {
opacity: 0;
}
.v-enter-active,
.v-leave-active {
transition: all 5s;
}
.v-enter-to,
.v-leave {
opacity: 1;
}
</style>
7.显性的过渡时间
在一些情况下,Vue可以自动得出过渡效果的完成时机,从而对dom进行处理。
但是有些时候,我们会设置一系列的过渡效果,例如嵌套元素也有过渡动效,其过渡效果的时间长于父元素。此时我们可以设置duration属性,定制一个显性的过渡持续时间(以毫秒记):
<transition :duration="1000">...</transition>
<transition :duration="{ enter:400,leave:600 }">...</transition>
也可以定制进入和移出的持续时间:
<transition :duration="{ enter: 500, leave: 800 }">...</transition>
8.初始渲染的过渡
可以通过 appear
attribute 设置节点在初始渲染的过渡。
和进入/离开过渡一样,同样也可以自定义 CSS 类名。如:
appear-class="appear-enter"
appear-active-class="appear-enter-active"
appear-to-class="appear-enter-to"
<template>
<div class="demo">
<button @click="show = !show">click</button>
<transition
:duration="1000"
appear //进入就显示
appear-active-class="animated swing"
enter-active-class="animated tada"
leave-active-class="animated tada"
>
<div class="box" v-if="show">hello world</div>
</transition>
</div>
</template>
9.JavaScript 钩子
可以在属性中声明 JavaScript 钩子:
<transition
@before-enter="beforeEnter" //入场前
@enter="enter" //中
@after-enter="afterEnter" //后
@enter-cancelled="enterCancelled" //取消,用的很少
@before-leave="beforeLeave"
@leave="leave"
@after-leave="afterLeave"
@leave-cancelled="leaveCancelled"
>
<!-- ... -->
</transition>
<template>
<div class="demo">
<button @click="show = !show">click</button>
<transition
:css="false"
@before-enter="beforeEnter"
@enter="enter"
@after-enter="afterEnter"
@enter-cancelled="enterCancelled"
>
<div class="box" v-if="show">hello world</div>
</transition>
</div>
</template>
<script>
export default {
data () {
return {
show: true,
x: 200,
}
},
methods: {
beforeEnter (el) {
el.style.transform = 'translateX(200px)';
},
enter (el, done) {
//done.canceled = true;//一旦动画取消,就会执行enterCancelled函数
const timer = setInterval(() => {
this.x -= 2;
el.style.transform = `translateX(${
this.x}px)`;
if(this.x <= 0) {
clearInterval(timer);
done();//done不执行,after就不会执行
}
}, 10)
},
afterEnter () {
this.x = 200;
},
enterCancelled: function () {
// console.log('cancel');
// this.isCancel = true;
}
}
}
</script>
<style scoped>
button {
margin-bottom: 10px;
}
.box {
width: 100px;
height: 100px;
margin-bottom: 10px;
line-height: 100px;
text-align: center;
border: 1px solid red;
color: red;
}
</style>
- before-enter 动画入场前,可以在其中设置元素开始动画之前的起始样式
- enter 动画入场中,可以在其中写动画
- after-enter 动画完成后
- enter-cancelled 取消动画
对于仅使用 JavaScript 过渡的元素添加 v-bind:css=“false”,Vue 会跳过 CSS 的检测。这也可以避免过渡过程中 CSS 的影响。
设置了 appear 特性的 transition 组件,也存在自定义 JavaScript 钩子:
<transition
appear
v-on:before-appear="customBeforeAppearHook"
v-on:appear="customAppearHook"
v-on:after-appear="customAfterAppearHook"
v-on:appear-cancelled="customAppearCancelledHook"
>
<!-- ... -->
</transition>
结合 Velocity.js
继续懒,所以有了js的动画插件
Velocity.js 官网地址:http://velocityjs.org/
安装方式:npm install velocity-animate
<template>
<div class="demo">
<button @click="show = !show">click</button>
<transition
:css="false"
@before-enter="beforeEnter"
@enter="enter"
@before-leave="beforeLeave"
@leave="leave"
>
<div class="box" v-if="show">hello world</div>
</transition>
</div>
</template>
<script>
export default {
data () {
return {
show: true,
}
},
methods: {
beforeEnter (el) {
el.style.opacity = 0;
},
enter (el, done) {
Velocity(el, {
opacity: 1}, {
duration: 500});
Velocity(el, {
rotateZ: 10 }, {
duration: 300 });
Velocity(el, {
rotateZ: -10 }, {
duration: 300 });
Velocity(el, {
rotateZ: 0 }, {
duration: 300, complete: done });
},
beforeLeave (el) {
el.style.transformOrigin = 'left';
},
leave (el, done) {
Velocity(el, {
translateX: '15px', rotateZ: '50deg'}, {
duration: 600});
Velocity(el, {
rotateZ: '100deg'}, {
duration: 600, loop: 2});
Velocity(el, {
rotateZ: '45deg', translateY: '30px', translateX: '30px', opacity: 0}, {
complete: done});
},
}
}
</script>
<style scoped>
button {
margin-bottom: 10px;
}
.box {
width: 200px;
margin-bottom: 10px;
text-align: center;
border: 1px solid red;
color: red;
}
</style>