轮播的原理是每一帧都选出一个当前元素,前一个元素,后一个元素而后排成一行,最后改变这三个元素的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