进入(v-enter)/离开(v-leave)/移动(v-move)&列表(transition-group)的过渡
简单的例子:
<div id="demo">
<button @click="show = !show"> Toggle </button>
<transition name="fade">
<p v-if="show">hello</p>
</transition>
</div>
new Vue({
el: '#demo',
data: { show: true }
})
.fade-enter-active, .fade-leave-active {
transition: opacity .5s;
}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
opacity: 0;
}
1. 使用 <transition> 标签包裹需要过渡动画的元素,vue会在适当时候给元素添加类名。
2. 被 <transition> 标签包裹的元素需要使用条件渲染("v-if"/"v-show")。
3. 在 <transition> 标签内的 "name" 属性为动画提供具名,也可能缺省,则以 "v-" 作为前缀。
4. 以上配置并不会在首次渲染生效,使用 "appear" 属性解决,具体查看下面的 "初始渲染的过渡" 。
注意,若 "v-if"/"v-show" 放在组件内部,只会产生"进入过度"。解决办法是把 "v-if"/"v-show" 放在父组件中。错误示范如下:
<div id="container">
<button @click="isShow=!isShow">显示/隐藏</button>
<transition>
<child/>
<!-- <child v-if="isShow"> --> <!-- 正确做法 -->
</transition>
</div>
<script>
Vue.component('child',{
template: '<div v-if="$root.isShow" style="background:green;width:100px;height:100px;">子组件</div>'
});
new Vue({
el: '#container',
data() { return { isShow: false } }
});
</script>
<style>
.v-enter-active, .v-leave-active { transition: opacity .5s; }
.v-enter, .v-leave-to { opacity: 0; }
</style>
初始渲染的过渡:
<!-- 添加 appear 属性后可在首次渲染有 enter 过渡动画 -->
<transition appear><!-- ... --></transition>
<!-- 同样可以指定自定义类名及JS钩子函数,具体做法查看官方文档 -->
过渡的类名( 6个 ):
1. v-enter:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。
2. v-enter-active:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。
3. v-enter-to: 定义进入过渡的结束状态。在元素被插入之后下一帧生效 (与此同时 v-enter 被移除),在过渡/动画完成之后移除。
4. v-leave: 定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。
5. v-leave-active:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。
6. v-leave-to: 定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时 v-leave 被删除),在过渡/动画完成之后移除。
CSS动画:[ animation ]
.bounce-enter-active {
animation: bounce-in .5s;
}
.bounce-leave-active {
animation: bounce-in .5s reverse;
}
@keyframes bounce-in {
0% { transform: scale(0); }
50% { transform: scale(1.5); }
100% { transform: scale(1); }
}
自定义过渡的类名:[ 结合第三方css库: animate.css ]
<!-- 引入 animate.css 库 -->
<link href="https://cdn.jsdelivr.net/npm/animate.css@3.5.1" rel="stylesheet" type="text/css">
<div id="example-3">
<button @click="show = !show">
Toggle render
</button>
<!-- 以属性方式指定特定类名 -->
<transition
name="custom-classes-transition"
enter-active-class="animated tada"
leave-active-class="animated bounceOutRight"
>
<p v-if="show">hello</p>
</transition>
</div>
animate.css库使用方法:
在官网(https://daneden.github.io/animate.css/)上找到合适的动画,如上方法添加指定的类名(必须带有"animated"类名)。
持续时长:
同时使用过渡(transition)和动画(animation),可能存在时长不同,使用 type 特性并设置 animation 或 transition 来明确以哪个为时长标准。
<!-- 以 transition 时长为标准 -->
<transition type="transition">...</transition>
为 <transition> 标签添加具体持续时长:
<!-- 定制一个显性的过渡持续时间 (以毫秒计):-->
<transition :duration="1000">...</transition>
<!-- 你也可以定制进入和移出的持续时间:-->
<transition :duration="{ enter: 500, leave: 800 }">...</transition>
JS钩子函数: [ 结合第三方JS动画库: 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 })
}
}
})
1. 当只用 JavaScript 过渡的时候,在 enter 和 leave 中必须使用 done 进行回调。否则,它们将被同步调用,过渡会立即完成。
2. 推荐对于仅使用 JavaScript 过渡的元素添加 v-bind:css="false",Vue 会跳过 CSS 的检测。这也可以避免过渡过程中 CSS 的影响。
3. Velocity.js 的具体用法请查看文档(http://www.mrfront.com/docs/velocity.js/index.html)。
多个元素的过渡: [ transition标签内包含v-if/v-else ]
1. 默认情况下 <transition> 内的组件是进入/离开同时发生,要改变需要设置 "mode" 属性。
<!-- 先出后入,先入后出则输入"in-out" -->
<transition name="fade" mode="out-in">
<!-- ... the buttons ... -->
</transition>
2. 当有相同标签名的元素切换时,需要通过 key 特性设置唯一的值来标记以让 Vue 区分它们,否则 Vue 为了效率只会替换相同标签内部的内容。
<transition>
<button v-if="isEditing" key="save"> Save </button>
<button v-else key="edit"> Edit </button>
</transition>
列表过渡: [ transition-group标签内包含v-for ]
与transition类似。使用场景是,用v-for渲染列表,当数据源发生变化,对应的列表项需要过渡动画。有几点需要注意,过渡元素不可用(如v-mode="out-in");内部元素均需要唯一的"key"属性; <transition-group> 渲染呈现为真实标签,默认是"span",可以通过"tag"属性指定特有标签。
<div id="list-demo" class="demo">
<!-- 修改数据源的按钮 -->
<button v-on:click="add">Add</button>
<button v-on:click="remove">Remove</button>
<!-- transition-group 渲染为 p 标签 -->
<transition-group name="list" tag="p">
<span v-for="item in items" v-bind:key="item" class="list-item">
{{ item }}
</span>
</transition-group>
</div>
列表的排序过渡: [ v-move ]
与 enter/leave 用法类似,用 "v-move" 实现列表元素的移动,可以通过 name 属性来自定义前缀,也可以通过 move-class 属性手动设置。
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.14.1/lodash.min.js"></script> 操作数组的JS库 -->
<div id="flip-list-demo" class="demo">
<button v-on:click="shuffle">Shuffle</button>
<transition-group name="flip-list" tag="ul">
<!-- 改变数组顺序:shuffle(){this.items = _.shuffle(this.items)} -->
<li v-for="item in items" v-bind:key="item">
{{ item }}
</li>
</transition-group>
</div>
.flip-list-move {
transition: transform 1s;
}
进阶用法:https://jsfiddle.net/chrisvfritz/sLrhk1bc/
状态过渡
数值变化的过渡动画: [ TweenMax.js ]
<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>
new Vue({
el: '#animated-number-demo',
data: {
number: 0,
tweenedNumber: 0
},
computed: {
animatedNumber: function() {
return this.tweenedNumber.toFixed(0);
}
},
watch: {
// 监听数值变化,动态演示数值的增减,依赖TweenMax.min.js库
number: function(newValue) {
TweenLite.to(this.$data, 0.5, { tweenedNumber: newValue });
}
}
})
颜色变化的过渡动画:
方法与上述数值变化过渡动画类似,同样是获取值,使用指定库函数赋值,以达到动态显示变化的效果。
依赖 Tween.js 和 Color.js 。具体查看官方文档例子:https://cn.vuejs.org/v2/guide/transitioning-state.html#%E7%8A%B6%E6%80%81%E5%8A%A8%E7%94%BB%E4%B8%8E%E4%BE%A6%E5%90%AC%E5%99%A8。
其他数值变化的过渡动画,实现的效果原理也是类似的做法。