輪播的原理是每一幀都選出一個當前元素,前一個元素,後一個元素而後排成一行,最後改變這三個元素的translate來觸發css3的transition進行動畫,當有touch事件的時候,要實時改變各個元素的位置,因此要把transition關閉。組件demo地址 m.cm233.comjavascript
<template> <section class="shuffling-wrapper"> <ul :class="['shuffling-bar',{trans : open, transnext: openNext, transpre: openPre}]"> <template v-for="item in shufflingData"> <li :class="['item', { pre: $index == preIndex && shufflingData.length > 2, next: $index == nextIndex && shufflingData.length > 2, current: $index == shufflingIndex}]" :style="translateObj[$index]" @touchstart="shufflingData.length > 2 && touchStart($event)" @touchmove.prevent="shufflingData.length > 2 && touchMove($event)" @touchend="shufflingData.length > 2 && touchEnd($event)"> <a class="link" href="{{item.link}}"> <img class="img" :src="item.img" alt="{{item.subject}}"> </a> </li> </template> <li class="shuffling-btn"> <i class="btn-item" :style="{width: btnWidth+'px', transform: 'translate3d('+(shufflingIndex*100)+'%,0,0)'}"></i> </li> </ul> </section> </template>
.shuffling-wrapper{ width: 100%; } .shuffling-bar{ position: relative; width: 100%; overflow: hidden; padding-top: 70.66%; .item{ position: absolute; top: 0; bottom: 0; left: 0; right: 0; margin: auto; z-index: 100; user-select: none; -webkit-touch-callout:none; -webkit-tap-highlight-color: transparent; } .link{ display: block; width: 100%; height: 100%; } .img{ display: block; width: 100%; height: 100%; } .current{ transform: translate3d(0, 0, 0); z-index: 300; } .pre{ transform: translate3d(-100%, 0, 0); z-index: 300; } .next{ transform: translate3d(100%, 0, 0); z-index: 300; } } .trans{ .current{ transition: transform .3s ease-in-out; } } .transpre{ .pre{ transition: transform .3s ease-in-out; } } .transnext{ .next{ transition: transform .3s ease-in-out; } } .shuffling-btn{ height: 3px; background-color: rgba(255,255,255,.8); position: relative; z-index: 400; .btn-item{ position: absolute; top: 0; left: 0; height: 3px; background-color: #e81926; border-radius: 1px; transition: transform .3s ease-in-out; } }
import {getClient} from '../vuex/getters' export default{ ready: function(){ //初始化 this.caculateIndex(); //計算初始前一個元素,當前元素,後一個元素 this.autoScroll(); //開始自動輪播 }, props: { shufflingData: { type: Array, default: () => [] } }, data(){ let that = this; return { shufflingIndex: 0, //當前元素的index nextIndex: 0, //後一個元素的序列 preIndex: 0, //前一個元素的序列 timer: 0, // 儲存循環的計時器序號 translateObj: {},//touch事件時用來記錄移動位置並應用到style中 open: true, // 當前元素的動畫開關 openNext: false, // 後一個元素的動畫開關 openPre: true, // 前一個元素的動畫開關 timeOut: false, // 和setTimeout一塊兒可確保touch事件和以後的小動畫完成後再執行自動輪播 moveOpen: false, btnWidth: 0 } }, watch: { 'shufflingData' : function(val){ this.btnWidth = this.clientInfo.width/this.shufflingData.length; this.caculateIndex(); } }, methods: { touchStart(event){ if(!this.timeOut){ let that = this; that.startX = event.changedTouches[0].pageX; //初始位置 this.open = false; this.openPre = false; this.openNext = false; this.moveOpen = true; } }, touchMove(event){ if(this.moveOpen){ this.movingX = event.changedTouches[0].pageX; //移動中的位置 this.percent = ((this.movingX-this.startX)/this.clientInfo.width)*100; //須要響應到style中的transform屬性添加,必需要用$set方法,不然不會響應到視圖 this.$set('translateObj[preIndex].transform','translate3d('+(this.percent-100)+'%, 0, 0)'); this.$set('translateObj[nextIndex].transform','translate3d('+(this.percent+100)+'%, 0, 0)'); this.$set('translateObj[shufflingIndex].transform','translate3d('+(this.percent)+'%, 0, 0)'); } }, touchEnd(){ if(!this.timeOut){ this.moveOpen = false; this.timeOut = true; this.open = true; this.openPre = true; this.openNext = true; this.$set('translateObj[preIndex].transform',''); this.$set('translateObj[nextIndex].transform',''); this.$set('translateObj[shufflingIndex].transform',''); if(this.percent <= -30){ //假如向左滑了30%,則向左移動一屏,向左移動一屏須要關掉下一個元素的動畫開關,不然後後一屏的元素會飛過去 this.sufflingChange(); //向右側滾動(包含最後一個元素時的處理) this.openNext = false; }else if(this.percent >= 30){ //假如向右滑了30%,則向右移動一屏,向右移動一屏須要關掉前一個元素的動畫開關,不然前前一屏的元素會飛過去 if(this.shufflingIndex == 0){ //向左側滾動(包含第一個元素的處理) this.shufflingIndex = this.shufflingData.length-1; }else{ this.shufflingIndex--; } this.openPre = false; this.caculateIndex(); } setTimeout(() => { //確保移動後的動畫完成,延遲和動畫時間設置一致 this.autoScroll(); this.timeOut = false; }, 300); } }, autoScroll(){ //進行自動輪播 let that = this; clearInterval(that.timer); that.openNext = false; that.openPre = true; that.timer = setInterval(that.sufflingChange,4000); }, sufflingChange(){ //向右側滾動 if(this.shufflingIndex == this.shufflingData.length - 1){ this.shufflingIndex = 0; }else{ this.shufflingIndex++; } this.caculateIndex(); }, caculateIndex(){ //計算上一個元素和下一個元素的index this.preIndex = this.shufflingIndex - 1 < 0 ? this.shufflingData.length-1 : this.shufflingIndex - 1; this.nextIndex = this.shufflingIndex + 1 >= this.shufflingData.length ? 0 : this.shufflingIndex + 1; } }, vuex:{ getters: { clientInfo : getClient } } }
經過寫這個組件對vue的數據驅動視圖的思想更瞭解了,感受vue和css3真是一對好基友!用起來超級舒服!css
使用時新建一個組件,把對應部分copy進去就能夠了,好比組件叫shuffling.vue, 引入時html
<shuffling :shuffling-data = 'shuffling'></shuffling>
import Shuffling from '../components/Shuffling' export default { data(){ return{ shuffling: [ { link: 'www.baidu.com', img: 'src.alicdn.com/fdfdfd.jpg', subject: '233333' }, { link: 'www.baidu.com', img: 'src.alicdn.com/fdfdfd.jpg', subject: '233333' }, { link: 'www.baidu.com', img: 'src.alicdn.com/fdfdfd.jpg', subject: '233333' } ] } }, components: { Shuffling } }
組件暫時還未對2個之內的數組作兼容,2個之內將不會執行動畫,只有圖片切換效果。輪播進度條目前是墨瞳官網所示的輪播樣式。想要改一下也會很是簡單,只要利用好shufflingIndex這個屬性就好了。
組件中還有一個clientInfo,這個對象是瀏覽器寬高的對象,個人項目中是存在vuex裏的,由於不少組件都會用到,若是不須要vuex的話,能夠直接寫在組件裏。
組件的原理註釋中都寫的很清楚了,理解之後能更好的應用vue