概述
轮播的原理是每一帧都选出一个当前元素,前一个元素,后一个元素然后排成一行,最后改变这三个元素的translate来触发css3的transition进行动画,当有touch事件的时候,要实时改变各个元素的位置,所以要把transition关闭。组件demo地址 m.cm233.com
<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真是一对好基友!用起来超级舒服!
使用方法及注意事项
使用时新建一个组件,把对应部分copy进去就可以了,比如组件叫shuffling.vue, 引入时
<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的话,可以直接写在组件里。
组件的原理注释中都写的很清楚了,理解以后能更好的应用