【重点突破】—— Vue2.0 transition 动画Demo实践填坑
前言:vue1.0版本和2.0版本的过渡系统改变是很大的,具体请详看文档介绍。本文转载自郭锦荣的博客,一共列举了四种transition的使用实践,分别是css过渡、css动画、javascript钩子、列表过渡的应用,这里只作为学习梳理。
css过渡--实践 |
Demo效果:
实现思路:通过一个transition来触发多个子元素的过渡效果,我们只需要定义元素对应的过渡效果就可以。
其他事情vue会帮我们搞定,由此可以扩展出其他酷炫的过渡场景效果。
代码实现:
<template> <div class="app"> <button @click="showMenu" class="btn">{{text}}</button> <transition name="move"> <div class="menu" v-show="show"> <div class="inner inner-1">1</div> <div class="inner inner-2">2</div> <div class="inner inner-3">3</div> </div> </transition> </div> </template> <script type="text/ecmascript-6"> export default { data () { return { show: false }; }, methods: { showMenu () { this.show = !this.show; } }, computed: { text () { return this.show ? '收' : '开'; } } }; </script> <style lang="stylus" rel="stylesheet/stylus"> .app .btn position: fixed bottom: 50px right: 10px z-index: 10 width: 50px height: 50px line-height: 50px border-radius: 50% border: none outline: none color: #fff font-size: 18px background: blue .menu position: fixed bottom: 50px right: 10px width: 50px height: 50px border-radius: 50% transition: all .7s ease-in &.move-enter-active .inner transform: translate3d(0, 0, 0) transition-timing-function: cubic-bezier(0, .57, .44, 1.97) .inner-1 transition-delay: .1s .inner-2 transition-delay: .2s .inner-3 transition-delay: .3s &.move-enter, &.move-leave-active .inner transition-timing-function: ease-in-out .inner-1 transform: translate3d(0, 60px, 0) transition-delay: .3s .inner-2 transform: translate3d(40px, 40px, 0) transition-delay: .2s .inner-3 transform: translate3d(60px, 0, 0) transition-delay: .1s .inner display: inline-block position: absolute width: 30px height: 30px line-height: 30px border-radius: 50% background: red text-align: center color: #fff transition: all .4s .inner-1 top: -50px left: 10px .inner-2 left: -30px top: -30px .inner-3 left: -50px top: 10px </style>
可以看到我们的代码基本主要是完成css过渡效果的样式,而触发过渡效果只是简单地通过一个click事件就搞定了。
vue会自动嗅探目标元素是否有 CSS 过渡或动画,并在合适时添加/删除 CSS 类名。
css 动画--实践 |
Demo效果:
这个案例的不同之处在于过渡效果是使用css动画来实现。
<template> <div class="app"> <button @click="showball" class="btn">show</button> <transition name="move" type="animation"> <div class="ball" v-show="show"> <div class="inner"></div> </div> </transition> </div> </template> <script type="text/ecmascript-6"> export default { data () { return { show: false }; }, methods: { showball () { this.show = !this.show; } } }; </script> <style lang="stylus" rel="stylesheet/stylus"> @keyframes shape-change { 0%, 100% { border-radius: 50% background: red } 50% { border-radius: 0 background: blue } } @keyframes moveball-in { 0% { transform: translate3d(300px,-200px,0) } 50% { transform: translate3d(100px,-400px,0) } 100% { transform: translate3d(0,0,0) } } @keyframes moveball-out { 0% { transform: translate3d(0,0,0) } 50% { transform: translate3d(100px,-400px,0) } 100% { transform: translate3d(300px,-200px,0) } } .app .btn width: 40px height: 30px margin-top: 40px border: none outline: none background: red color: #fff .ball position: absolute bottom: 20px left: 20px width: 50px height: 50px transition: all 1s cubic-bezier(.22,-0.86,.97,.58) &.move-enter-active opacity: 1 animation: moveball-in 1s .inner animation: shape-change 1s &.move-leave-active opacity: 0.8 animation: moveball-out 1s .inner animation: shape-change 1s .inner display: inline-block width: 30px height: 30px border-radius: 50% background: red transition: all 1s linear </style>
实现思路:只需要在vue过渡类名下加了不同的animation。
官网说明:当只使用transition或animation其中一种时,vue是能自动监听对应的类型的,但是如果同一个元素同时使用两种效果,就需要明确指定监听哪一种类型。
其实这个demo已经简单地实现同时使用两种类型的情况,可以看到有一个透明度的变化。
注意: 假如animation里使用了transform,并且外面也使用了transform的话,那么元素在过渡的时候动画效果就会有冲突,效果就有点出入了。
JavaScript钩子 -- 实践 |
前两个Demo都是有进入和离开的过渡,但是如果一些场景只需要进入过渡然后就结束了,那么这时就可以使用JavaScript钩子结合CSS transitions/animations来实现,当然也可以单独使用。
Demo效果:
使用场景:这个一个非常low的模拟炮弹发射的场景,可以看到小球有抛物线轨迹运动的过渡,而且发射出去就不会再回来了
关键代码:
<template> <div class="app"> <div class="gun" @click="launch($event)"></div> <div class="shells-wrapper"> <transition v-for="shell in shells" name="launch-shell" @before-enter="beforeEnter" @enter="enter" @after-enter="afterEnter"> <div class="shell" v-show="shell.show"> <div class="inner"></div> </div> </transition> </div> <div class="goal"></div> </div> </template>
误区:由于本身这个案例是一组元素的过渡,所以很容易就会觉得用Vue2.0提供的transition-group不就行了。
纠正:transition-group是列表过渡,要使用的那一组元素是相关联的、互相影响的。
而这个案例的元素每个都是独立的,只不过是一组独立的元素过渡,所以还是用transition+v-for实现一组相同元素过渡。
JavaScript钩子实现过渡:
export default { data () { return { shells: [ { show: false }, { show: false }, { show: false } ] }; }, methods: { launch (event) { for (let i = 0; i < this.shells.length; i++) { let shell = this.shells[i]; if (!shell.show) { shell.show = true; shell.target = event.target; return; } } }, beforeEnter (el) { let count = this.shells.length; while (count--) { let shell = this.shells[count]; if (shell.show) { let rect = shell.target.getBoundingClientRect(); let left = rect.left - 32; let top = -(window.innerHeight - rect.top - 15); el.style.display = ''; el.style.webkitTransform = `translate3d(0,${top}px,0)`; el.style.transform = `translate3d(0,${top}px,0)`; let inner = el.getElementsByClassName('inner')[0]; inner.style.webkitTransform = `translate3d(${left}px,0,0)`; inner.style.transform = `translate3d(${left}px,0,0)`; } } }, enter (el, done) { /* eslint-disable no-unused-vars */ let refresh = el.offsetHeight; this.$nextTick(() => { el.style.webkitTransform = 'translate3d(0,0,0)'; el.style.transform = 'translate3d(0,0,0)'; let inner = el.getElementsByClassName('inner')[0]; inner.style.webkitTransform = 'translate3d(0,0,0)'; inner.style.transform = 'translate3d(0,0,0)'; }); done(); }, afterEnter (el) { let ball = this.shells[0]; ball.show = false; el.style.display = 'none'; } } };
- 过渡元素就不需要为其添加vue的过渡css类名了,只需在元素本身添加transition即可,那vue在之前css过渡的时候会自动帮我们去添加对应的类名来完成过渡效果。
- javascript钩子需要我们自己完成这个始末状态的设置。
- 当我们点击触发一个过渡的时候,在beforeEnter里先拿到当前元素的偏移位置,然后给过渡元素设置其起始位置,在enter里需要重新触发下浏览器的重绘,然后在下一帧重新设置元素的结束位置,这时就会产生过渡效果,在过渡完成后我们将当前元素隐藏即可。
transition-group -- 实践 |
Demo效果:
使用场景:这个Demo是一个简单的todo lists,当其中一个元素过渡的时候,会影响其他元素的过渡。当然,删除按钮其实本身也是一个transition过渡,也就是说可以在transition-group里使用transition。
关键代码:
<template> <div class="app"> <button @click="add" class="add-btn">+</button> <transition-group name="slide" tag="ul" class="list-wrapper"> <li class="list" v-for="(item, index) in lists" v-touch:swipeleft="showBtn.bind(this, index)" v-touch:swiperight="hideBtn.bind(this, index)" :key="item"> <span class="text">{{item.text}}</span> <transition name="move"> <button class="del-btn" @click="delList(index)" v-show="item.show">删除</button> </transition> </li> </transition-group> </div> </template>
坑:之前看官网列表过渡的例子,它是一个数组,元素都是数字,并且每一项都必须设置唯一的key值。
所以学着在完成demo的时候将索引值index传给key,结果过渡不对,换成对应的item就正常了。
这个Demo用到了vue-touch,虽然github上说不支持2.0版本了,但是有一个next分支是支持的,只需在项目下安装它即可:
(sudo) npm install --save git://github.com/vuejs/vue-touch.git#next #sudo mac环境使用
关键样式:
.list display: flex width: 100% height: 40px line-height: 40px margin-bottom: 10px color: #666 font-size: 14px background: #eee transition: all .4s &.slide-move transition: transform 1s &.slide-enter transform: translate3d(-100%, 0, 0) &.slide-leave-active position: absolute transform: translate3d(-100%, 0, 0) &:last-child margin-bottom: 0 .del-btn flex: 0 0 60px border: none outline: none color: #fff background: red transition: all .4s &.move-enter, &.move-leave-active transform: translate3d(70px, 0, 0) .text flex: 1 padding-left: 20px
如果改变定位过渡的duration与进入离开一样的话,其实可以不用-move。这里设置-move的过渡的duration不同于元素进入离开的duration产生一种速度差,看起来舒服点。而且-leave-active需要设置position: absolute才会有效果。现在看来其实列表过渡也是很容易实现的。
注:转载请注明出处
- vue2.0 transition -- demo实践填坑
- vue2.0 transition -- demo实践填坑
- vue2.0 transition -- demo实践填坑
- Vue2.0 transition | demo 实践填坑
- vue2.0 transition -- demo实践填坑
- vue2.0 transition -- demo实践填坑
- Vue2.0过渡动画效果transition
- vue2.0+基础知识连载(18)--- 动画(transition)
- vue2.0-transition动画
- vue2.0 中使用transition实现动画效果使用心得
- vue2.0使用animate.css动画,transition&transition-group
- vue2.0 keep-alive最佳实践
- vue2.0 开发实践总结之入门篇
- Vuex2.0+Vue2.0构建备忘录应用实践
- Vue2.0 Component的详解(重点)
- Vue-router2.0基础实践
- iOS CATransition动画Demo
- vue.bootstrap.demo.和vue动画和简单介绍JavaScript数据类型之隐式类型转换
- vue-router2学习实践笔记(附DEMO)
- vue.js中Vue-router 2.0基础实践教程