閱讀目錄
1.理解VUE---過渡效果
1. 過渡的-css-類名
會有4個(css) 類名在 enter/leave 在過渡中切換。
1. v-enter: 進入過渡的開始狀態。在元素被插入時生效,在下一個幀移除。
2. v-enter-active: 進入過渡的結束狀態。在元素被插入時生效,在 transition/animation 完成之後移除。
3. v-leave 離開過渡的開始狀態。在離開過渡被觸發時生效,在下一個幀移除。
4. v-leave-active 離開過渡的結束狀態。在離開過渡被觸發時生效,在 transition/animation 完成之後移除。
看如下圖所示:
在enter/leave 過渡中切換的類名,v- 是類名的字首,使用 <transition name="my-transition"> 可以重置字首,比如 v-enter 替換為 my-transition-enter。
看如下demo
<!DOCTYPE html> <html> <head> <title>演示Vue</title> <style> .fade-enter-active, .fade-leave-active { transition: opacity .5s } .fade-enter, .fade-leave-active { opacity: 0 } </style> </head> <body> <div id='app'> <button v-on:click="show = !show">toggle</button> <transition name='fade'> <p v-if="show">hello</p> </transition> </div> </body> <script src="./vue.js"></script> <script type="text/javascript"> new Vue({ el: '#app', data: { show: true } }) </script> </html>
如上程式碼; 給transition標籤 定義了一個name屬性,因此過渡的css類名中的字首v被替換成fade,定義了 .fade-enter-active, .fade-leave-active {transition: opacity .5s } 過渡動畫,定義進入過渡的結束狀態和離開過渡的結束狀態 為透明度0 在0.5s之內完成。
我們還可以定義如下的css,實現動畫,如下css程式碼:
.fade-enter-active { transition: all .5s ease; } .fade-leave-active { transition: all .8s cubic-bezier(1.0, 0.5, 0.8, 1.0); } .fade-enter, .fade-leave-active { transform: translateX(10px); opacity: 0; }
2. css動畫
css動畫用法同css過渡一樣, 區別是在動畫中 v-enter 類名在節點插入DOM後不會立即刪除,而是在animationend事件觸發時刪除。如下程式碼也可以用在css動畫下。
<!DOCTYPE html> <html> <head> <title>演示Vue</title> <style> .fade-enter-active { animation: fade-in .5s; } .fade-leave-active { animation: fade-out .5s; } @keyframes fade-in { 0% { transform: scale(0); } 50% { transform: scale(1.5); } 100% { transform: scale(1); } } @keyframes fade-out { 0% { transform: scale(1); } 50% { transform: scale(1.5); } 100% { transform: scale(0); } } </style> </head> <body> <div id='app'> <button v-on:click="show = !show">toggle</button> <transition name='fade'> <p v-if="show">hello</p> </transition> </div> </body> <script src="./vue.js"></script> <script type="text/javascript"> new Vue({ el: '#app', data: { show: true } }) </script> </html>
3. 自定義過渡類名
上面的四個過渡類名都是根據transition的name屬性自動生成的,下面我們可以通過以下特性來自定義過渡類名。
enter-class
enter-active-class
leave-class
leave-active-class
以上的優先順序都高於普通類名,通過以上的 我可以自定義類名寫不同的樣式了,如下程式碼:
如下使用的animate.css裡面的樣式實現動畫:如下程式碼:
<!DOCTYPE html> <html> <head> <title>演示Vue</title> <link href="https://unpkg.com/animate.css@3.5.1/animate.min.css" rel="stylesheet" type="text/css"> </head> <body> <div id='app'> <button v-on:click="show = !show">toggle</button> <transition name="custom-classes-transition" enter-active-class="animated tada" leave-active-class="animated bounceOutRight" > <p v-if="show">hello</p> </transition> </div> </body> <script src="./vue.js"></script> <script type="text/javascript"> new Vue({ el: '#app', data: { show: true } }) </script> </html>
4. 多個元件的過渡
多個元件的過渡可以使用動態元件實現,如下程式碼:
<!DOCTYPE html> <html> <head> <title>演示Vue</title> <style> .component-fade-enter-active, .component-fade-leave-active { transition: opacity .3s ease; } .component-fade-enter, .component-fade-leave-active { opacity: 0; } </style> </head> <body> <div id='app'> <input v-model='view' type='radio' value='v-a' name="view" /> <label for='a'>A</label> <input v-model='view' type='radio' value='v-b' name='view' /> <label for='b'>B</label> <transition name='component-fade' mode='out-in'> <component v-bind:is='view'></component> </transition> </div> </body> <script src="./vue.js"></script> <script type="text/javascript"> new Vue({ el: '#app', data: { view: 'v-a' }, components: { 'v-a': { template: '<div>Component A</div>' }, 'v-b': { template: '<div>Component B</div>' } } }) </script> </html>
5. javascript鉤子函式
除了使用css過渡的動畫來實現vue的元件過渡,還可以使用javascript鉤子函式來實現。在鉤子函式中直接操作dom。我們在屬性中宣告如下鉤子。
程式碼如下:
<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> new Vue({ el: '#app', data: { view: 'v-a' }, methods: { // 過渡進入 設定過渡進入之前的元件狀態 beforeEnter: function(el) { }, // 設定過渡進入完成時的元件狀態 enter: function(el, done) { // done() }, // 設定過渡進入完成之後的元件狀態 afterEnter: function(el) { // .... }, enterCancelled: function(el) { // ... }, // 過渡離開 設定過渡離開之前的元件狀態 beforeLeave: function(el) { // 。。。。 }, // 設定過渡離開完成時的元件狀態 leave: function(el, done) { // ... done() }, // 設定過渡離開完成之後的元件狀態 afterLeave: function(el) { // ...... }, leaveCancelled: function(el) { // .... } } })
注意:
1. 只用 JavaScript 過渡的時候, 在 enter 和 leave 中,回撥函式 done 是必須的 。 否則,它們會被同步呼叫,過渡會立即完成。
2. 推薦對於僅使用 JavaScript 過渡的元素新增 v-bind:css="false",Vue 會跳過 CSS 的檢測。這也可以避免過渡過程中 CSS 的影響。
下面是vue教程上Velocity.js的一個demo,如下程式碼:
<!DOCTYPE html> <html> <head> <title>演示Vue</title> <style> </style> </head> <body> <div id='app'> <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> </body> <script src="./vue.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.js"></script> <script type="text/javascript"> new Vue({ el: '#app', data: { show: true }, 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> </html>
理解過渡模式:
如下demo
<!DOCTYPE html> <html> <head> <title>演示Vue</title> <style> .no-mode-fade-enter-active, .no-mode-fade-leave-active { transition: opacity .5s } .no-mode-fade-enter, .no-mode-fade-leave-active { opacity: 0; } </style> </head> <body> <div id='app'> <transition name='no-mode-fade'> <button v-if='on' key='on' @click='on=false'>on</button> <button v-else='' key='off' @click='on=true'>off</button> </transition> </div> </body> <script src="./vue.js"></script> <script type="text/javascript"> new Vue({ el: '#app', data: { on: false } }) </script> </html>
執行一下,在上面的on按鈕 和 off按鈕的過渡中,兩個按鈕都被重繪了,一個離開過渡的時候另一個開始進入過渡。這是 <transition> 的預設行為 - 進入和離開同時發生。
但是我們在元素絕對定位在彼此之上的時候執行正常:如下程式碼:
<!DOCTYPE html> <html> <head> <title>演示Vue</title> <style> .wrap { position: relative; height: 18px; } .wrap button { position: absolute; } .no-mode-fade-enter-active, .no-mode-fade-leave-active { transition: opacity .5s } .no-mode-fade-enter, .no-mode-fade-leave-active { opacity: 0; } </style> </head> <body> <div id='app'> <div class='wrap'> <transition name='no-mode-fade'> <button v-if='on' key='on' @click='on=false'>on</button> <button v-else='' key='off' @click='on=true'>off</button> </transition> </div> </div> </body> <script src="./vue.js"></script> <script type="text/javascript"> new Vue({ el: '#app', data: { on: false } }) </script> </html>
我們加上 translate 讓它們運動像滑動過渡:程式碼如下:
<!DOCTYPE html> <html> <head> <title>演示Vue</title> <style> .wrap { position: relative; height: 18px; } .wrap button { position: absolute; } .no-mode-fade-enter-active, .no-mode-fade-leave-active { transition: all 1s } .no-mode-fade-enter, .no-mode-fade-leave-active { opacity: 0; } .no-mode-fade-enter { transform: translateX(31px); } .no-mode-fade-leave-active { transform: translateX(-31px); } </style> </head> <body> <div id='app'> <div class='wrap'> <transition name='no-mode-fade'> <button v-if='on' key='on' @click='on=false'>on</button> <button v-else='' key='off' @click='on=true'>off</button> </transition> </div> </div> </body> <script src="./vue.js"></script> <script type="text/javascript"> new Vue({ el: '#app', data: { on: false } }) </script> </html>
同時生效的進入和離開的過渡不能滿足所有要求,所以 Vue 提供了 過渡模式
in-out: 新元素先進行過渡,完成之後當前元素過渡離開。
out-in: 當前元素先進行過渡,完成之後新元素過渡進入。
用 out-in 重寫之前的開關按鈕過渡:如下程式碼:
<!DOCTYPE html> <html> <head> <title>演示Vue</title> <style> .no-mode-fade-enter-active, .no-mode-fade-leave-active { transition: opacity .5s } .no-mode-fade-enter, .no-mode-fade-leave-active { opacity: 0; } </style> </head> <body> <div id='app'> <div class='wrap'> <transition name='no-mode-fade' mode='out-in'> <button v-if='on' key='on' @click='on=false'>on</button> <button v-else='' key='off' @click='on=true'>off</button> </transition> </div> </div> </body> <script src="./vue.js"></script> <script type="text/javascript"> new Vue({ el: '#app', data: { on: false } }) </script> </html>
in-out 滑動淡出demo如下:
<!DOCTYPE html> <html> <head> <title>演示Vue</title> <style> .wrap { position: relative; height: 18px; } .wrap button { position: absolute; } .no-mode-fade-enter-active, .no-mode-fade-leave-active { transition: all .5s } .no-mode-fade-enter, .no-mode-fade-leave-active { opacity: 0; } .no-mode-fade-enter { transform: translateX(31px); } .no-mode-fade-leave-active { transform: translateX(-31px); } </style> </head> <body> <div id='app'> <div class='wrap'> <transition name='no-mode-fade' mode='in-out'> <button v-if='on' key='on' @click='on=false'>on</button> <button v-else='' key='off' @click='on=true'>off</button> </transition> </div> </div> </body> <script src="./vue.js"></script> <script type="text/javascript"> new Vue({ el: '#app', data: { on: false } }) </script> </html>
5. VUE列表過渡實現輪播圖
列表過渡使用 <transition-group> 元件,不同於 <transition>:
1. 它會以一個真實元素呈現:預設為一個 <span>。你也可以通過 tag 特性更換為其他元素。
2. 內部元素 總是需要 提供唯一的 key 屬性值。
<!DOCTYPE html> <html> <head> <title>演示Vue</title> <style> * { margin:0; padding:0;} .carousel-wrap { position: relative; height: 280px; width: 520px; overflow: hidden; // 刪除 background-color: #fff; } .slide-ul { width: 100%; height: 100%; } .slide-ul li { position: absolute; width: 100%; height: 100%; } .slide-ul li img { width: 100%; height: 100%; } .carousel-items { position: absolute; z-index: 10; bottom: 10px; width: 100%; margin: 0 auto; text-align: center; font-size: 0; } .carousel-items span { display: inline-block; height: 6px; width: 30px; margin: 0 3px; background-color: #b2b2b2; cursor: pointer; } .carousel-items span.active { background-color: red; } .list-enter-active { transition: all 1s ease; transform: translateX(0) } .list-leave-active { transition: all 1s ease; transform: translateX(-100%) } .list-enter { transform: translateX(100%) } .list-leave { transform: translateX(0) } </style> </head> <body> <div id='carousel' class='carousel-wrap'> <transition-group tag='ul' class='slide-ul' name='list'> <li v-for='(list, index) in slideList' :key='index' v-show='index===currentIndex' @mouseenter='stop' @mouseleave='go'> <a :href='list.href'> <img :src='list.image' :alt='list.desc'> </a> </li> </transition-group> <div class='carousel-items'> <span v-for="(item, index) in slideList.length" :class="{'active':index===currentIndex}" @mouseover="change(index)">{{index}}</span> </div> </div> </body> <script src="./vue.js"></script> <script type="text/javascript"> new Vue({ el: '#carousel', data: { slideList: [ { 'href': '', 'desc': '1111', 'image': 'http://img.alicdn.com/tfs/TB1vHswQVXXXXXMXFXXXXXXXXXX-520-280.png_q90_.webp' }, { 'href': '', 'desc': '2222', 'image': 'http://img.alicdn.com/tfs/TB1c9kFQVXXXXcoXpXXXXXXXXXX-520-280.jpg_q90_.webp' }, { 'href': '', 'desc': '3333', 'image': 'https://aecpm.alicdn.com/tps/i1/TB1r4h8JXXXXXXoXXXXvKyzTVXX-520-280.jpg' } ], currentIndex: 0, timer: '' }, methods: { create: function() { var self = this; // DOM載入完成後,下個tick中開始輪播 this.$nextTick(function(){ self.timer = setInterval(function(){ self.autoPlay(); }, 4000) }) }, go: function() { var self = this; self.timer = setInterval(function(){ self.autoPlay(); },4000) }, stop: function() { var self = this; clearInterval(self.timer); self.timer = null; }, change: function(index) { this.currentIndex = index; }, autoPlay: function() { this.currentIndex++; if(this.currentIndex > this.slideList.length - 1) { this.currentIndex = 0; } } } }) </script> </html>