单元素/组件的过渡
在以下情形中,transition
封装组件,可以给任何元素和组件添加进入/离开过渡
- 条件渲染(v-if)
- 条件展示(v-show)
- 动态组件
- 组件根节点?
过渡的类名
v-enter
v-enter-active
v-enter-to
v-leave
v-leave-active
v-leave-to
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <div id="root"> <transition name="fade"> <div v-if="show">hello world</div> </transition>
<button @click="handleClick">切换</button> </div> <script> let vm = new Vue({ el: '#root', data: { show: true }, methods: { handleClick() { this.show = !this.show } } }) </script>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| .fade-enter, .fade-leave-to{ opacity: 0; } .fade-enter-active, .fade-leave-active { transition: opacity 1s; }
.v-enter, .v-leave-to{ opacity: 0; } .v-enter-active, .v-leave-active{ transition: opacity 1s; }
|
css过渡
1 2 3 4 5 6 7 8
| <div id="example-1"> <button @click="show = !show"> Toggle render </button> <transition name="slide-fade"> <p v-if="show">hello</p> </transition> </div>
|
1 2 3 4 5 6
| new Vue({ el: '#example-1', data: { show: true } })
|
1 2 3 4 5 6 7 8 9 10 11 12 13
|
.slide-fade-enter-active { transition: all .3s ease; } .slide-fade-leave-active { transition: all .8s cubic-bezier(1.0, 0.5, 0.8, 1.0); } .slide-fade-enter, .slide-fade-leave-to { transform: translateX(10px); opacity: 0; }
|
css动画
@keyframes
定义一个动画名字,然后在过渡类名中animation: xxx 1s
;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| @keyframes bounce-in{ 0% { transform: scale(0); } 50% { transform: scale(1.5); } 100% { transform: scale(1); } } .fade-enter-active{ transform-origin: left center; animation: bounce-in 1s; } .fade-leave-active{ transform-origin: left center; animation: bounce-in 1s reverse; }
.active{ transform-origin: left center; animation: bounce-in 1s; } .leave{ transform-origin: left center; animation: bounce-in 1s reverse; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| <link rel="stylesheet" href="./animate.css">
<div id="root"> <transition name="fade"> <div v-if="show">hello world</div> </transition> <br> <transition enter-active-class="active" leave-active-class="leave" > <div v-if="show">哈哈啊哈哈</div> </transition> <br> <transition enter-active-class="animated swing" leave-active-class="animated shake" > <div v-if="show">哇哦哇哦</div> </transition>
<button @click="handleClick">切换</button> </div> <script> let vm = new Vue({ el: '#root', data: { show: true }, methods: { handleClick() { this.show = !this.show } } }) </script>
|
同时使用过渡和动画
- 当同时使用二者时,在transition组件中设置
type=transition或animation
来声明Vue需要监听的类型
:duration="1000"
定制一个显性的过渡持续时间,以毫秒计
appear
表示设置节点初始渲染时的过渡,配合appear-active-class
等使用,也可以使用自定义类名custom-appear-to-class
等
1 2 3 4 5 6 7 8
| .fade-enter, .fade-leave-to{ opacity: 0; } .fade-enter-active, .fade-leave-active{ transition: opacity 3s }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| <link rel="stylesheet" href="./animate.css">
<div id="root"> <transition name="fade" type="transition" :duration = '5000' appear enter-active-class="animated swing fade-enter-active" leave-active-class="animated shake fade-leave-active" appear-active-class="animated swing" > <div v-if="show">哈哈啊哈哈</div> </transition>
<button @click="handleClick">切换</button> </div> <script> let vm = new Vue({ el: '#root', data: { show: true }, methods: { handleClick() { this.show = !this.show } } }) </script>
|
JS动画
JavaScript钩子
1 2 3 4 5 6 7 8 9 10 11 12 13
| <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>
|
- 这些钩子函数可以结合CSS
transition/animation
一起使用
- 当只用JavaScript过渡的时候,在
enter
和leave
中必须使用done
进行回调,否则,它们将会被同步调用,过渡会立即完成
- 推荐对当仅使用js过渡的元素添加
v-bind:css="false"
,Vue会跳过css检测,避免过渡过程中css影响
例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <script src="velocity.js"></script>
<div id="root"> <transition name="fade" @before-enter="handleBeforeEnter" @enter="handleEnter" @after-enter="handleAfterEnter"
@before-leave @leave @after-leve > <div v-show="show">Hello world</div> </transition>
<button @click="handleClick">toggle</button> </div>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| let vm = new Vue({ el: '#root', data: { show: true }, methods: { handleClick() { this.show = !this.show }, handleBeforeEnter(el){ el.style.opacity = 0; }, handleEnter(el,done){ Velocity(el,{opacity:1},{duration:1000,complete:done}) }, handleAfterEnter(el){ console.log('动画结束') } } })
|
多个元素或组件的过渡
- 当具有
相同标签名的元素
进行切换时,需要通过key
设置唯一标记
- 给
<transition>
组件中的多个元素设置key
是一个更好的实践时
过渡模式
in-out
不常用:新元素先进行过渡,完成后当前元素过渡离开
out-in
:当前元素先进行过渡,完成之后新元素过渡进入
多个组件的过渡
- 不需要使用
key
特性,只需要使用动态组件
-v-bind:is="type"
1 2 3 4 5 6 7 8
| .v-enter, .v-leave-to{ opacity: 0; } .v-enter-active, .v-leave-active{ transition: opacity 1s; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <div id="root"> <transition mode="in-out"> <div v-if="show" key="hello">Hello world</div> <div v-else key="bye">Bye world</div> </transition>
<br><br> <transition mode="out-in"> <child-one v-if="show"></child-one> <child-two v-else></child-two> </transition>
<br><br> <transition mode="out-in"> <component :is="type"></component> </transition>
<button @click="handleClick">toggle</button> </div>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| Vue.component('child-one',{ template:'<div>Child-one</div>' })
Vue.component('child-two',{ template:'<div>Child-two</div>' })
let vm = new Vue({ el: '#root', data: { show: true, type:'child-one' }, methods: { handleClick() { this.show = !this.show this.type = this.type==='child-one'?'child-two':'child-one' } } })
|
列表过渡
<transition-group>
列表过渡
过渡模式
不可用,如mode="in-out"
,因为我们不再相互切换特有的元素
- 内部元素总是需要提供唯一的
key
属性值
1 2 3 4 5 6
| .v-enter,.v-leave-to{ opacity: 0; } .v-enter-active,.v-leave-active{ transition: opacity 1s; }
|
1 2 3 4 5 6 7 8
| <div id="root"> <transition-group> <div v-for="(item,index) of list" :key="item.id"> {{item.title}} </div> </transition-group> <button @click="handleClick">Add</button> </div>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| let count = 0; let vm = new Vue({ el: '#root', data: { list: [] }, methods: { handleClick() { this.list.push({ id: count++, title:'hello world' }) } } })
|
动画封装
1 2 3 4 5 6 7 8 9 10 11
| <div id="root"> <fade :show="show"> <div>hello world</div> </fade>
<fade :show="show"> <h2>哈哈哈啊哈</h2> </fade> <button @click="handleClick">toggle</button> </div>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| Vue.component('fade',{ props:['show'], template:` <transition @before-enter="handleBeforeEnter" @enter="handleEnter"> <slot v-if="show"></slot> </transition> `, methods:{ handleBeforeEnter(el){ el.style.color = 'red' }, handleEnter(el,done){ setTimeout(() => { el.style.color done() }, 2000); } } })
let vm = new Vue({ el: '#root', data: { show:true }, methods: { handleClick() { this.show = !this.show } } })
|