Vue之过渡动画(一)
3.1、进入/离开 & 列表过渡
1. Overview
Vue provides a variety of ways to apply transition effects when items are inserted, updated, or removed from the DOM.
On this page, we’ll only cover **entering, leaving, **and list transitions, but you can see the next section for managing state transitions.
DOM操作时的过渡效果,让页面更丝滑。
2. 单元素/组件的过渡
先来个demo开开胃,完整代码
<style> .fade-enter-active, .fade-leave-active { transition: opacity .5s; } .fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ { opacity: 0; } </style> <div id="demo"> <button v-on:click="show = !show"> Toggle </button> <transition name="fade"> <p v-if="show">hello</p> </transition> </div> <script> new Vue({ el: '#demo', data: { show: true } }) </script>
2.1 过渡的类名(Transition Classes)
There are six classes applied for enter/leave transitions.
enter/leave过渡中,会有6个class切换
v-enter
v-enter-active
v-enter-to (2.1.8+)
v-leave
v-leave-active
v-leave-to (2.1.8+)
2.2 CSS过渡
即给上面例子中的 .fade-enter-active, .fade-leave-active 这些类名应用的CSS样式
2.3 CSS动画
写法差不多,就是把transition换成animation 完整代码
<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> <div id="example-2"> <button @click="show = !show">Toggle show</button> <transition name="bounce"> <p v-if="show">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris facilisis enim libero, at lacinia diam fermentum id. Pellentesque habitant morbi tristique senectus et netus.</p> </transition> </div> <script> new Vue({ el: '#example-2', data: { show: true } }) </script>
2.4 自定义过渡的类名
我们可以通过以下 attribute 来自定义过渡类名:
enter-class
enter-active-class
enter-to-class (2.1.8+)
leave-class
leave-active-class
leave-to-class (2.1.8+)
如下与 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> <script> new Vue({ el: '#example-3', data: { show: true } }) </script>
2.5 同时使用过渡和动画
要同时使用过渡和动画,要用type属性指明类型:animation or transition
2.6 指定过渡的时间
<transition :duration="1000">...</transition> <transition :duration="{ enter: 500, leave: 800 }">...</transition>
2.7 JavaScript钩子(JavaScript Hooks)
用js代码操作动画
如下使用了Velocity.js动画库,完整代码
<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> <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>
3. 初始渲染的过渡(Transitions on Initial Render)
If you also want to apply a transition on the initial render of a node, you can add the appear attribute:
一个DOM节点初始化渲染到页面时可以引用过渡效果
<transition appear> <!-- ... --> </transition> // 【还自定义class】 <transition appear appear-class="custom-appear-class" appear-to-class="custom-appear-to-class" (2.1.8+) appear-active-class="custom-appear-active-class" > <!-- ... --> </transition> // 【也可以自定义js钩子】 <transition appear v-on:before-appear="customBeforeAppearHook" v-on:appear="customAppearHook" v-on:after-appear="customAfterAppearHook" v-on:appear-cancelled="customAppearCancelledHook" > <!-- ... --> </transition>
4. 多个元素之间的过渡(Transitioning Between Elements)
一个常见的场景就是:渲染列表元素时,如果列表是空的,则渲染一个代表空列表的元素
<transition> <table v-if="items.length > 0"> <!-- ... --> </table> <p v-else>Sorry, no items found.</p> </transition>
需要注意:如果两个tag名一样的元素之间做过渡时,要加key demo如下:
<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> <div id="app"> <transition name="bounce"> <button v-bind:key="docState"> {{ buttonMessage }} </button> </transition> <button @click="savebutton">切换按钮</button> </div> <script> new Vue({ el: '#app', data: { docState: 'saved' }, computed:{ buttonMessage: function () { switch (this.docState) { case 'saved': return 'Edit' case 'edited': return 'Save' } } }, methods: { savebutton:function () { if(this.docState == 'edited'){ this.docState = 'saved' }else { this.docState = 'edited' } } } }) </script>
4.1 过渡模式
可以设置两种过渡模式:
in-out: New element transitions in first, then when complete, the current element transitions out.
out-in: Current element transitions out first, then when complete, the new element transitions in.
我们来对比下设置了out-in模式和不设置的区别吧:给上面例子上的transition加上mode属性为out-in
<transition name="bounce" mode="out-in"> <button v-bind:key="docState"> {{ buttonMessage }} </button> </transition>
加之前:
加之后:效果棒棒哒
5. 多个组件之间的过渡
组件之间的过渡更加简单,写法和元素一样,不需要加key:
<style> .component-fade-enter-active, .component-fade-leave-active { transition: opacity .3s ease; } .component-fade-enter, .component-fade-leave-to /* .component-fade-leave-active below version 2.1.8 */ { opacity: 0; } </style> <div id="app"> <input type="radio" value="v-a" id="a" name="view" @change="view='v-a'"> <label for="a">A</label> <input type="radio" value="v-b" id="b" name="view" @change="view='v-b'"> <label for="b">B</label> <transition name="component-fade" mode="out-in"> <component v-bind:is="view"></component> </transition> </div> <script> new Vue({ el: '#app', data: { view: 'v-a' }, components: { 'v-a': { template: '<div>Component A</div>' }, 'v-b': { template: '<div>Component B</div>' } } }) </script>
6. 列表过渡(List Transitions)
列表的Entering/Leaving过渡、Move Transitions移动过渡,用<transition-group>
有几个注意点:
渲染时会转换为实际元素,默认为span,可以加tag标签指定,如下例子中指定为 tag='p'
的内部元素上要加key
css过渡类是应用在内部元素上的,而不是 group/container itself.
6.1 List Entering/Leaving Transitions
<style> .list-complete-item { transition: all 1s; display: inline-block; margin-right: 10px; } .list-complete-enter, .list-complete-leave-to /* .list-complete-leave-active below version 2.1.8 */ { opacity: 0; transform: translateY(30px); } .list-complete-leave-active { position: absolute; } </style> <div id="list-demo"> <button v-on:click="shuffle">Shuffle</button> <button v-on:click="add">Add</button> <button v-on:click="remove">Remove</button> <transition-group name="list-complete" tag="p"> <span v-for="item in items" v-bind:key="item" class="list-complete-item"> {{ item }} </span> </transition-group> </div> <script> new Vue({ el: '#list-demo', data: { items: [1, 2, 3, 4, 5, 6, 7, 8, 9], nextNum: 10 }, methods: { randomIndex: function () { return Math.floor(Math.random() * this.items.length) }, add: function () { this.items.splice(this.randomIndex(), 0, this.nextNum++) }, remove: function () { this.items.splice(this.randomIndex(), 1) }, shuffle: function () { this.items = _.shuffle(this.items) } } }) </script>
6.2 List Move Transitions
上面演示了列表内元素进入/离开时的过渡效果,
为了列表中元素移动时的过渡效果,vue引入了v-move过渡类名,如下的:.flip-list-move
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.14.1/lodash.min.js"></script> <style> .flip-list-move { transition: transform 1s; } </style> <div id="flip-list-demo" class="demo"> <button v-on:click="shuffle">Shuffle</button> <transition-group name="flip-list" tag="ul"> <li v-for="item in items" v-bind:key="item"> {{ item }} </li> </transition-group> </div> <script> new Vue({ el: '#flip-list-demo', data: { items: [1,2,3,4,5,6,7,8,9] }, methods: { shuffle: function () { this.items = _.shuffle(this.items) } } }) </script>
6.3 列表使用Javascript钩子函数添加过渡效果
上面讲的都是列表用css进行过渡,列表也可以用js代码进行过渡,如下:
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script> <div id="staggered-list-demo"> <input v-model="query"> <transition-group name="staggered-fade" tag="ul" v-bind:css="false" v-on:before-enter="beforeEnter" v-on:enter="enter" v-on:leave="leave" > <li v-for="(item, index) in computedList" v-bind:key="item.msg" v-bind:data-index="index" >{{ item.msg }} </li> </transition-group> </div> <script> new Vue({ el: '#staggered-list-demo', data: { query: '', list: [ { msg: 'Bruce Lee' }, { msg: 'Jackie Chan' }, { msg: 'Chuck Norris' }, { msg: 'Jet Li' }, { msg: 'Kung Fury' } ] }, computed: { computedList: function () { var vm = this return this.list.filter(function (item) { return item.msg.toLowerCase().indexOf(vm.query.toLowerCase()) !== -1 }) } }, methods: { beforeEnter: function (el) { el.style.opacity = 0 el.style.height = 0 }, enter: function (el, done) { var delay = el.dataset.index * 150 setTimeout(function () { Velocity( el, { opacity: 1, height: '1.6em' }, { complete: done } ) }, delay) }, leave: function (el, done) { var delay = el.dataset.index * 150 setTimeout(function () { Velocity( el, { opacity: 0, height: 0 }, { complete: done } ) }, delay) } } }) </script>
7. 可复用的过渡
To create a reusable transition, all you have to do is place a <transition> or <transition-group>
组件的过渡也也可以不用,相当于一个壳子,壳子上带着过渡效果,你可以复用到别的地方
8. 动态过渡
Yes, even transitions in Vue are data-driven! The most basic example of a dynamic transition binds the name attribute to a dynamic property.
由于过渡效果的实现都是在<transition> or <transition-group> 组件上添加属性,那么这些属性的属性值根据不同条件也可以被指定不同的动态值。
这就是动态过渡的由来。让过渡更加灵活和随心所欲