过渡
过渡可以增强用户体验,我们不仅可以通过Css3来实现过渡效果,当然Vue也给我们提供了实现过渡效果的方式;Vue在实现元素过渡效果的时候会给元素默认添加6个Class类,结合V-if或V-show来实现过渡(视觉上我们感觉这六个class类是一次性添加的,实际上是分阶段添加的);
过渡的过程:进入:隐藏→显示和离开:显示→隐藏
图解:
6个类名
- v-enter:效果进入之前的初始状态
- v-enter-active:效果进入正在进行时
- v-enter-to:效果进入之后的结束状态
- v-leave:效果离开之前的初始状态
- v-leave-active:效果离开的正在进行时
- v-leave-to:效果离开之后的结束状态
实现步骤
- 创建Vue实例;
- 在HTML结构中添加
transition标签,并为过渡的元素节点绑定V-show或V-if(如果我们想要一打开页面就应用过渡效果可以给transition标签添加appear属性); - 设置值6个类对应的
style样式.
例子
<style>
/* 效果离开后的状态和进入前的状态写在一起 */
.v-enter,
.v-leave-to {
opacity: 0;
}
/* 效果进入后的状态和离开前的状态写在一起 */
.v-enter-to,
.v-leave {
opacity: 1;
}
/* 进行时的状态写在一起 */
.v-enter-active,
.v-leave-active {
transition: all 1.5s ease;
}
</style>
<div id="box">
<!-- 每点击一次按钮flag的值取反 -->
<button @click="flag=!flag">切换按钮</button>
<!-- transition这个标签是必须要添加的,里面包裹要实现过渡效果的元素节点 -->
<transition appear>
<h1 v-show="flag">你好,Vue过渡</h1>
</transition>
</div>
<script>
var vm =new Vue({
el: "#box",
data: {
// 定义flag用来切换元素不同的状态(显示or隐藏)
flag: "true"
},
methods: {
}
})
</script>
上面是一个简单的例子,我们发现一个问题,如果页面中有很多个过渡的元素节点,每个节点实现的过渡效果又不相同,我们没有办法区分怎么办,总不能给每一个元素都添加一个transition吧?或者给6个类名后边加上css选择器?这样肯定都是不太稳妥的。那么Vue就给我们提供了自定义的命名方式,便于我们识别过渡的元素节点。其实很简单请看下面↓
- 首先,需要在
transition标签上添加name属性,属性值(比如其中一个名字叫:onion)就是我们给某个元素节点添加过渡的名字; - 然后,我们在使用的时候就不需要在
V-enter\......而是onion-enter、.......
自定义transition名字
<style>
h1 {
background-color: #cfa;
width: 600px;
text-align: center;
margin: 10px auto;
}
/* 效果离开后的状态和进入前的状态写在一起 */
.v-enter,
.v-leave-to {
opacity: 0;
transform: translateX(-150px);
}
/* 效果进入后的状态和离开前的状态写在一起 */
.v-enter-to,
.v-leave {
opacity: 1;
}
/* 进行时的状态写在一起 */
.v-enter-active,
.v-leave-active {
transition: all 1.5s ease;
}
/* 自定义的过渡类名 */
.onion-enter,
.onion-leave-to {
opacity: 0;
transform: translateY(50px);
}
.onion-enter-to,
.onion-leave {
opacity: 1;
}
.onion-enter-active,
.onion-leave-active {
transition: all 1.5s ease;
}
</style>
<div id="box">
<!-- 每点击一次按钮flag的值取反 -->
<button @click="flag=!flag">切换按钮</button>
<!-- transition这个标签是必须要添加的,里面包裹要实现过渡效果的元素节点 -->
<transition appear>
<h1 v-show="flag">你好,Vue过渡</h1>
</transition>
<transition name="onion">
<h1 v-show="flag">这个是我自定义名字的Vue过渡</h1>
</transition>
</div>
<script>
var vm = new Vue({
el: "#box",
data: {
// 定义flag用来切换元素不同的状态(显示or隐藏)
flag: "true"
},
methods: {
}
})
</script>
过渡+第三方animate实现炫酷效果
上面的效果特别炫酷,当然不是我徒手写的了,是我们利用第三方的插件结合Vue来实现的。如何实现呢?非常简单
步骤(我们采用本地引入animate.min.css文件的方式)
- 官方下载(animate.style/)animate.mi…
- 然后在transition标签中指定两个属性
enter-active-class和leave-active-class(规定的名字别乱改) - 最后分别给这两个类的值设置为
animate__animated 入场动画和animate__animated 出场动画
动画的钩子函数(了解)
transition组件为我们提供了8个钩子函数可以实现在动画呈现的不同时机做不同的事情。这八个钩子函数可以理解成是动画的生命周期:
- before-enter=“beforeEnter“ :进入过渡运行前
- enter=“enter“ :进入过渡运行时
- after-enter=“afterEnter“ :进入过渡运行后
- @enter-cancelled=“enterCancelled“ :进入过渡被打断时
- before-leave=“beforeLeave“ :离开过渡运行前
- leave=“leave“ :离开过渡运行时
- after-leave=“afterLeave“ :离开过渡运行后
- leave-cancelled=“leaveCancelled“ :离开过渡被打断时 v-on绑定指定的钩子事件,执行自己定义的事件方法
<style>
.mybtn {
width: 100px;
height: 100px;
background-color: red;
transform: translateX(50px);
}
.fade-enter-active,
.fade-leave-active {
transition: all 2s;
}
.fade-enter {
opacity: 0;
transform: translateX(0px);
}
.fade-enter-to {
opacity: 1;
transform: translateX(50px);
}
.fade-leave {
opacity: 1;
transform: translateX(50px);
}
.fade-leave-to {
opacity: 0;
transform: translateX(0px);
}
</style>
<div>
<button @click="flag=!flag">显示/隐藏</button>
<transition name='fade'
@before-enter="beforeEnter"
@enter="enter"
@after-enter="afterEnter"
@enter-cancelled="enterCancelled"
@before-leave="beforeLeave"
@leave="leave"
@after-leave="afterLeave"
@leave-cancelled="leaveCancelled">
<div v-show="flag" class="mybtn"></div>
</transition>
</div>
let vm= new Vue({
data:{
flag:false
},
methods:{
beforeEnter(){
alert("beforeEnter 进入过渡开始前 " );
},
enter(){
alert("enter 进入过渡状态开始");
},
afterEnter(){
alert("afterEnter 进入过渡状态结束");
},
enterCancelled(){
alert("enterCancelled 进入过渡状态 被打断");
},
beforeLeave(){
alert("beforeLeave 离开过渡开始前 " );
},
leave(){
alert("leave 离开过渡状态开始");
},
afterLeave(){
alert("afterLeave 离开过渡状态结束");
},
leaveCancelled(){
alert("leaveCancelled 离开过渡状态 被打断");
}
}
}).$mount('div');
methods:{
//动画钩子函数的第一个参数:el,表示 要执行动画的那个DOM元素,是个原生的 JS DOM对象
afterEnter(el) {
el.style.background='blue';
},
afterLeave(el){
el.style.background='red';
}
}
单向动画(半场动画)
如果要定义半场动画,做法是:直接在methods中写入场动画的函数,不写离场动画的函数即可。
例如:加购一件物品,会有一个小图标飞入购物车
<div id="app">
<input type="button" value="加入购物车" @click="flag=!flag">
<!-- 1. 使用 transition 元素把 小球包裹起来 -->
<transition @before-enter="beforeEnter" @enter="enter" @after-enter="afterEnter">
<div class="ball" v-show="flag"></div>
</transition>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
flag: false
},
methods: {
beforeEnter(el) {
// beforeEnter 表示动画入场之前,此时,动画尚未开始,可以 在 beforeEnter 中,设置元素开始动画之前的起始样式
// 设置小球开始动画之前的 起始位置
el.style.transform = "translate(0, 0)" // 一开始的时候,让小球处于(0,0)的位置
},
enter(el, done) {
// 【注意1】el.offsetWidth 这句话,没有实际的作用,但是,如果不写,出不来动画效果。可以认为 el.offsetWidth 会强制动画刷新
el.offsetWidth
// enter 表示动画 开始之后的样式,这里,可以设置小球完成动画之后的,结束状态
el.style.transform = "translate(150px, 300px)" // smyhvae 提示:让小球从(0,0)移动到 (150px, 300px)
el.style.transition = 'all 1s ease'
// 【注意2】这里的 done, 起始就是 afterEnter 这个函数,也就是说:done 是 afterEnter 函数的引用
done()
},
afterEnter(el) {
// 动画完成之后,会调用 afterEnter
// 动画结束后,让小球消失(直接让 flag 取反即可)
this.flag = !this.flag // 因为最开始的时候,小球就是处于消失的状态,这行代码可以让小球的动画重新开始
}
}
});
</script>
多个元素的联动过渡
需求:点击添加按钮后,给新增的 item 加个动画,其他的item也要是过渡的效果。
在实现列表过渡的时候,如果需要过渡的元素是v-for循环出来的,不能使用transition组件,需要使用transition-group组件。transition-group组件包裹的列表,必须声明key属性。
<style>
.v-enter,.v-leave-to{
opacity: 0;
transform: translateY(80px);
}
.v-enter-active,.v-leave-active{
transition: all 0.6s linear;
}
</style>
<!-- 被transition-group包裹的元素,会默认套上一层span,可以通过tag属性来指定外层包裹的标签-->
<div id ="app">
<label>ID:<input type="text" v-model="id"></label>
<label>name:<input type="text" v-model="name"></label>
<button @click="add">添加</button>
<transition-group>
<li v-for="(item,i) in list" :key="item.id">{{item.id}}---{{item.name}}---<button @click="del(i)">删除</button></li>
</transition-group>
</div>
<script>
//创建Vue实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
id:"",
name:"",
list:[
{id:1,name:"宋江"},
{id:2,name:"卢俊义"},
{id:3,name:"公孙胜"},
{id:4,name:"关胜"}
]
},
methods: {
add(){
//将用户输入的值添加到list列表中
this.list.push({id:this.id,name:this.name});
//将输入框清空
this.id = this.name = ""
},
//删除函数:将元素从list中删去。
del(i){
this.list.splice(i,1);
}
}
});
</script>
当我删除第2个item时,第3、第4个item在往上移动的过程比会较突兀。
/* 能够实现列表后续的元素,渐渐地漂上来的效果 */
.v-leave-active {
position: absolute;
}
改进:transition-group的tag属性
上面的代码中,我们审查一下代码元素会发现,用transition-group包裹的元素,会被默认套上一层<span>:
这个<span>虽然没有太大副作用,但是不符合代码规范。为了解决这个问题,我们可以通过tag属性给transition-group包谷的元素套上一层<ul>,然后把现有的<ul>注释掉,就可以了。