前言:vue1.0版本和2.0版本的過渡系統改變是很大的,具體請詳看文檔介紹。本文轉載自郭錦榮的博客,一共列舉了四種transition的使用實踐,分別是css過渡、css動畫、javascript鉤子、列表過渡的應用,這裏只做爲學習梳理。javascript
css過渡--實踐 |
Demo效果:css
實現思路:經過一個transition來觸發多個子元素的過渡效果,咱們只須要定義元素對應的過渡效果就能夠。html
其餘事情vue會幫咱們搞定,由此能夠擴展出其餘酷炫的過渡場景效果。vue
代碼實現:java
<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事件就搞定了。git
vue會自動嗅探目標元素是否有 CSS 過渡或動畫,並在合適時添加/刪除 CSS 類名。github
css 動畫--實踐 |
Demo效果:web
這個案例的不一樣之處在於過渡效果是使用css動畫來實現。shell
<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。npm
官網說明:當只使用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'; } } };
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纔會有效果。如今看來其實列表過渡也是很容易實現的。