Vue过渡动画

一、Vue中的动画实现原理

Vue实际上是通过动态地给< transition >
标签包裹的内容添加class,然后结合css对不同的class实现不同样式,最终实现动画效果

二、Vue过渡的实现方式

  1. 单个元素
<div id="box">
        <button @click="isShow=!isShow">click</button>
        <transition name="fade">
            <div v-show="isShow">Vue1</div>
        </transition>
</div>
		.fade-enter-active,.fade-leave-active{
            transition: all 1.5s;
        }
        .fade-enter,.fade-leave-to{
            opacity: 0;
            transform: translateX(100px);
        }
var vm = new Vue({
        el:"#box",
        data:{
            isShow:false
        }
    })

< transition >若没有设置name属性,那么默认为v-enter、v-enter-active和v-leave、v-leave-to
在这里插入图片描述
Vue会帮我们在合适的时机使用它们。比如在实现淡入时:
在这里插入图片描述
第一帧动画,会自动添加fade-enter和fade-enter-active类

第二帧动画,会去掉fade-enter类,添加fade-enter-to类

第三帧动画,会去掉所有enter类
在这里插入图片描述
淡出也是如此。

  1. Vue使用animate.css动画库
    我们知道在过渡类名中v-enter-active和v-enter-active这两个class在元素执行过渡或动画的过程中一直存在。所以我们可以省略除了v-enter-active和v-enter-active外其他class,使用关键帧@keyframes来控制元素动画的初始和结束状态。
    首先我们可以自定义过渡类名mybounce:
<div id="box">
        <transition name="mybounce">
            <div v-show="isShow">Vue2</div>
        </transition>
</div>
		.mybounce-enter-active{
            animation: bounce-in .5s;
        }
        .mybounce-leave-active{
            animation: bounce-in .5s reverse;
        }
        @keyframes bounce-in {
            0%{
                opacity: 0;
                transform: translateX(100px);
            }
            100%{
                opacity: 1;
                transform: translateX(0px);
            }
        }

既然我们可以使用自定义class,那么我们就可以使用开源的第三方CSS库,比如animate.css库
使用很简单,直接替换上面我们自定义的class就行。

<div id="box">
        <h1 class="animate__animated animate__bounce">animated</h1>
        <h2 class="animate__animated animate__pulse">animated</h2>
</div>

将animate__animated以及任何动画名称添加到元素中即可。(不要忘记animate__前缀!)

3.Vue中同时使用过渡和动画
先简单的用两个animated动画

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"/>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <title>Title</title>
</head>
<body>

<div id="app">
    <transition
            enter-active-class="animate__animated animate__bounce"
            leave-active-class="animate__animated animate__bounce"
    >
        <h1 v-if="show">Hello</h1>
    </transition>

    <button @click="handleBtnClick">{{btnText}}</button>
</div>

<script type="text/javascript">
    var vm = new Vue({
        el: '#app',
        data: {
            show: true,
            btnText: '显示',
        },
        methods: {
            handleBtnClick: function(){
                this.show = !this.show;
                this.btnText = this.btnText === '显示'? '隐藏' : '显示';
            },
        }
    });
</script>
</body>
</html>

我们点击change的时候特效是正常的,但是当我们重新刷新页面的时候会发现第一次渲染的时候,并没有效果出来,那么如果我现在想要页面刷新的时候就有特效出来该怎么做呢?

    <transition
            appear
            appear-active-class="animate__animated animate__bounce"
            enter-active-class="animate__animated animate__bounce"
            leave-active-class="animate__animated animate__bounce"
    >
        <h1 v-if="show">Hello</h1>
    </transition>

apper表示页面第一次渲染出来就需要显示效果,效果的内容是appear-active-class

保存刷新,发现直接就有特效出来了。

我们现在用的antimate动画其实是用keyframes写的css效果,但是如果我们想要transiton的过渡效果和antimate动画效果一起使用怎么办呢?

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Hello</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"/>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <style type="text/css">
        .fade-enter{
            opacity: 0;
        }
        .fade-enter-active{
            transition: opacity 3s;
        }
        .fade-leave-to{
            opacity: 0;
        }
        .fade-leave-active{
            transition: opacity 3s;
        }
    </style>
</head>
<body>
<div id="vm">

    <transition
            name="fade"
            enter-active-class="animate__animated animate__bounce fade-enter-active"
            leave-active-class="animate__animated animate__bounce fade-enter-active">
        <div v-if="show">Hello World</div>
    </transition>

    <button @click="handleClick" type="button">change</button>
</div>
<script>
    var vm = new Vue({
        el: '#vm',
        data: {
            show: true
        },
        methods: {
            handleClick: function() {
                this.show = !this.show;
            }
        }
    });
</script>
</body>
</html>

现在既有keyframes这种CSS动画,又有transiton这种过渡动画,

我们自己设置的transtion这种动画是3s,那么animate这种动画效果,查看源码可以看到是1s。在这里插入图片描述
那么,整个动画是以什么时长为结束时长呢?Vue自己也搞不清楚以哪个为结束时长,所以这个时候我们可以手动设置transition的type属性。
type="transition"则以过渡的时长为准,type="animation"以动画时长为准。
我们还可以利用:duration来自定义时长。

    <transition
            name="fade"
            :duration:"2000"
            enter-active-class="animate__animated animate__bounce fade-enter-active"
            leave-active-class="animate__animated animate__bounce fade-enter-active">
        <div v-if="show">Hello World</div>
    </transition>

还可以分别定义入场和出场动画时长。

<transition
            name="fade"
            :duration="{enter:2000,leave:5000}"
            enter-active-class="animate__animated animate__bounce fade-enter-active"
            leave-active-class="animate__animated animate__bounce fade-enter-active">
        <div v-if="show">Hello World</div>
</transition>
  1. JS钩子函数

js动画是通过绑定在上的钩子函数完成的。

<transition
	@before-appear     					都是第一次打开页面(刷新)
	@appear     
	@after-appear

	@before-enter="beforeEnter"			进入动画前执行
	@enter="enter"						进入动画时执行
	@after-enter="afterEnter"		    进入动画完成后,在enter中调用done()告诉vue,js动画结束才会触发

    @before-leave="beforeLeave"
    @leave="leave"
    @after-leave="afterLeave"
>
</transition>

在定义的方法中都会接收到一个参数

methods: {
		beforeEnter: function(el){	//这里接收到的el就是transition包裹这的dom元素
			el.style.color='red';
	}
		enter: function(el,done){
			done();		只有调用这个回调函数,Vue才知道动画执行结束
		}
		afterEnter: function(el){
				}
}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>钩子函数与动画</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"/>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>

<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>

<script>
    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 })
            }
        }
    })
</script>
</body>
</html>

可以在 attribute 中声明 JavaScript 钩子,这些钩子函数可以结合transitions/animations 使用,也可以单独使用。

注意:(1)推荐对于仅使用 JavaScript 过渡的元素添加 v-bind:css=“false”,Vue 会跳过 CSS 的检测。这也可以避免过渡过程中 CSS 的影响。(2)当只用 JavaScript 过渡的时候,在 enter 和 leave 中必须使用 done 进行回调。否则,它们将被同步调用,过渡会立即完成。

  1. 多个元素的过渡
<div id="box">
        <button @click="isShow=!isShow">click</button>
        <transition name="mybounce" mode="out-in">
            <p v-if="isShow" key="1" >Vue1</p>
            <p v-else key="2">Vue2</p>
        </transition>
    </div>-->
		.mybounce-enter-active{
            animation: bounce-in .5s;
        }
        .mybounce-leave-active{
            animation: bounce-in .5s reverse;
        }
        @keyframes bounce-in {
            0%{
                opacity: 0;
                transform: translateX(100px);
            }
            100%{
                opacity: 1;
                transform: translateX(0px);
            }
        }

由于因Vue的复用机制,若不指定key值,Vue不会对dom进行创建和删除操作而会直接复用,所以动画不会执行。可给元素添加唯一key值来使vue对该元素不进行复用。

  1. 多个组件的过渡
    多个组件的过渡动画注意的就只有一点:在动态组件外层包裹一个transition就行了,模式使用mode去控制。
 .v-enter , .v-leave-to {
            opacity: 0;
        }
        .v-enter-active , .v-leave-active {
            transition: opacity 2s;
        }
<div id="box">
    <transition mode="in-out">
        <component :is="type"></component>
    </transition>
    <button @click="handleClick">toggle</button>
</div>
 Vue.component('child',{
        template:'<div>child</div>'
    });
    Vue.component('child-one',{
        template:'<div>child-one</div>'
    })

    var vm = new Vue({
        el: "#box",
        data: {
            type: 'child',
        },
        methods: {
            handleClick: function() {
                this.type = this.type === 'child'?'child-one':'child';
            }
        }
    })
  1. 列表过渡
    当我们希望对列表进行过渡效果时,使用transition-group标签就可以了。
    (1)不同于 < transition >,它会以一个真实元素呈现:默认为一个 < span >。也可以通过 tag属性更换为其他元素。
    (2)过渡模式(mode)不可用
    (3)内部元素总是需要提供唯一的 key attribute 值。
    (4)CSS 过渡的类将会应用在内部的元素中,而不是这个组/容器本身。
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>列表过渡</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <style>
        .fade-enter,
        .fade-leave-to{
            opacity: 0;
        }
        .fade-enter-active,
        .fade-leave-active{
            transition: opacity 1s;
        }
    </style>
</head>
<body>
<div id="box">
    <transition-group name="fade">
        <div v-for="item of list" :key="item.id">{{item.title}}-----{{item.id}}</div>
    </transition-group>
    <button @click="handleClick">添加</button>
</div>
<script>
    let vm = new Vue({
        el: '#box',
        data: {
            count:0,
            list:[]
        },
        methods: {
            handleClick() {
                this.list.push({
                    id:this.count ++,
                    title:'hello world'
                })
            }
        }
    })
</script>
</body>
</html>

transition-group标签相当于在每一个< span >标签外层都加了一个transition标签,把列表的过渡转化为单个元素的过渡。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值