0
点赞
收藏
分享

微信扫一扫

【Vue】Vue学习笔记——过渡与动画

杰森wang 2022-01-24 阅读 119

文章目录


4. 过渡与动画

过渡是Vue为DOM动画效果提供了一个特性,Vue在插入、更新或移除DOM时,提供多种不同方式的应用过渡效果,包括以下工具:

  • 在CSS过渡和动画中自动应用class
  • 可以配合使用第三方CSS动画库,如Animate.css
  • 在过渡钩子函数中使用JavaScript直接操作DOM
  • 可以配合使用第三方JavaScript动画库,如Velocity.js

4.1 元素/组件过渡

Vue提供了transition的封装组件,在下列情形中,可以给任意元素和组件添加进入/离开过渡

  • 条件渲染(使用v-if)
  • 条件展示(使用v-show)
  • 动态组件
  • 组件根节点

组件过渡应用:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <!--引入vue-->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="demo">
    <button v-on:click="show = !show">
        点我
    </button>
    <transition name="fade">
        <p v-if="show">动画实例</p>
    </transition>
</div>
<script>
    new Vue({
        el: '#demo',
        data: {
            show: true
        }
    })
</script>
</body>
</html>

实例中通过单击"点我"按钮将变量show的值从true变为false。如果值为true则显示子元素p标签的内容。

下面这段代码展示了transition标签包裹了p标签:

<transition name="fade">
    <p v-if="show">动画实例</p>
</transition>

当插入或删除包含在transition组件中的元素时,Vue将会进行以下处理:

  • 自动嗅探目标元素是否应用了CSS过渡或动画。如果是,则在恰当的时机添加/删除CSS类名
  • 如果过渡组件提供了JavaScript钩子函数,这些钩子函数将在恰当的时机被调用
  • 如果没有找到钩子函数也没有检测到CSS过渡/动画,DOM操作(插入/删除)在下一帧立即执行

4.2 使用过渡类实现动画

过渡其实就是一个淡入淡出的效果。Vue在元素显示与隐藏的过渡中提供了以下6个class进行切换:

  • v-enter:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入的下一帧移除。
  • v-enter-avtive:定义进入过渡生效时的状态。在进入整个过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以用来定义进入过渡的过程时间、延迟和曲线函数。
  • v-enter-to:Vue2.1.8版本及以上定义进入过渡的结束状态。在元素被插入之后的下一帧生效(与此同时v-enter移除),在过渡/动画完成之后移除。
  • v-leave:定义离开过渡的开始状态。在离开过渡触发时立即生效,下一帧被移除。
  • v-leave-active:定义离开过渡时的生效状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立即生效,在过渡/动画完成之后移除。这个类可以用来定义离开过渡的过程时间、延迟和曲线函数。
  • v-leave-to:Vue2.1.8版本及以上定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效(与此同时v-leave移除),在过渡/动画完成之后移除。

原理如图:
在这里插入图片描述
对于这些在过渡中切换的类名来说,如果使用一个没有名字的,则v-是这些类名的默认前缀。如果使用了,那么v-enter会被替换为v-transition-enter。

v-enter-active和v-leave-active可以控制进入/离开过渡的不同的缓和曲线。

4.2.1 CSS过渡

常用的Vue过渡效果使用CSS过渡transition。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <!--引入vue-->
    <script src="/vue.js"></script>
    <style>
        .fade-enter{
            opacity: 0;
        }
        .fade-enter-active{
            transition: opacity 1s;
        }
        .fade-leave-to{
            opacity: 0;
        }
        .fade-leave-active{
            transition: opacity 1s;
        }
    </style>
</head>
<body>
<div id="app">
    <button @click="show=!show">点我</button>
    <transition name="fade">
        <div v-if="show">Hello world</div>
    </transition>
</div>
<script>
    new Vue({
        el: '#app',
        data: {
            show: true
        }
    })
</script>
</body>
</html>

当动画执行的一瞬间会自动在div上增加两个class名字,分别是fade-enter和fade-enter-active,因为transition标签的name是fade。

当动画执行到第二帧时,Vue又会把fade-enter删除,然后添加一个fade-enter-to,再当动画执行到结束的一瞬间,Vue又把fade-enter-active和fade-enter-to删除。

如果在transition标签纸不添加name属性,默认会自动添加name=“v”,那么class属性也会如下:

<style>
    .v-enter{
        opacity: 0;
    }
    .v-enter-active{
        transition: opacity 1s;
    }
    .v-leave-to{
        opacity: 0;
    }
    .v-leave-active{
        transition: opacity 1s;
    }
</style>

4.2.2 CSS动画

CSS动画animation用法与CSS过渡transition相同。区别在于动画中v-enter类名在结点插入DOM后不会立即删除,而是在animationend事件触发时被删除。

例:在元素enter和leave时都增加缩放scale效果

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <!--引入vue-->
    <script src="/vue.js"></script>
    <style>
        .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);}
        }
    </style>
</head>
<body>
<div id="app">
    <button v-on:click="show = !show">点我</button>
    <transition name="bounce">
        <p v-if="show">Hello World</p>
    </transition>
</div>
<script>
    new Vue({
        el: '#app',
        data: {
            show: true
        }
    })
</script>
</body>
</html>

Vue为了检测到过渡的完成,必须设置相应的事件监听器。它可以是transitionend或animationend,这取决于元素所采用的CSS规则。如果使用其中任何一种,则Vue能自动识别类型并监听。

在一些场景中需要将一个元素同时设置两种过渡动效,例如animation很快地被触发并完成了,而transition效果还没结束。在这种情况下,就需要使用type特性并设置animation或transition来明确声明Vue监听的类型。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <!--引入vue-->
    <script src="/vue.js"></script>
    <style>
        .fade-enter,.fade-leave-to{
            opacity:0;
        }
        .fade-enter-active,.fade-leave-active{
            transition:opacity 1s;
            animation:bounce-in 5s;
        }
        @keyframes bounce-in{
            0%{transform:scale(0);}
            50%{transform:scale(1.5);}
            100%{transform:scale(1);}
        }
    </style>
</head>
<body>
<div id="app">
    <button v-on:click="show = !show">点我</button>
    <transition name="fade" type="transition">
        <p v-if="show">Hello World</p>
    </transition>
</div>
<script>
    new Vue({
        el: '#app',
        data: {
            show: true,
        },
    })
</script>
</body>
</html>

4.2.3 自定义过渡的类名

我们可以通过以下特性来自定义过渡的类名

  • enter-class
  • enter-active-class
  • leave-class
  • leave-avtive-class

它们的优先级高于普通的类名,这对于Vue的过渡系统和其他第三方CSS动画库来讲,如与Animate.css结合使用十分有用:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <!--引入vue-->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <style>
        .fade-in-active, .fade-out-active{
            transition: all 1.5s ease
        }
        .fade-in-enter, .fade-out-active{
            opacity: 0
        }
    </style>
</head>
<body>
<div id="app">
    <button @click="show = !show">
        点我
    </button>
    <transition
            name="fade"
            enter-class="fade-in-enter"
            enter-active-class="fade-in-active"
            leave-class="fade-out-enter"
            leave-active-class="fade-out-active"
    >
        <p v-show="show">hello</p>
    </transition>
</div>
<script>
    new Vue({
        el: '#app',
        data: {
            show: true
        }
    })
</script>
</body>
</html>

上面代码中,原来默认的fade-enter类对应的fade-in-enter,而fade-enter-active对应的fade-in-active。

4.2.4 CSS过渡钩子函数

除了可以用CSS过渡的动画来实现Vue组件过渡,还可以用JavaScript的钩子函数来实现,在钩子函数中直接操作DOM。可以在属性中声明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>

js代码块如下:

//...
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的影响。

Vue.js也可以和一些JavaScript动画库配合使用,这里只需调用JavaScript钩子函数,而不需要定义CSS样式。transition接受选项css.false,将直接跳过CSS检测,避免CSS规则干扰过渡,而且需要在enter和leave钩子函数中调用done函数,明确过渡结束时间。此处将引入Velocity.js配合使用JavaScript过渡:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <!--引入vue-->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <!--
Velocity 和 jQuery.animate 的工作方式类似,也是用来实现 JavaScript 动画的一个很棒的选择
-->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script>
</head>
<body>
<div id="app">
    <button @click="show = !show">
        点我
    </button>
    <transition
            v-on:before-enter="beforeEnter"
            v-on:enter="enter"
            v-on:leave="leave"
            v-bind:css="false"
    >
        <p v-if="show">
            Hello
        </p>
    </transition>
</div>
<script>
    new Vue({
        el: '#app',
        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>
举报

相关推荐

0 条评论