Vue 组件封装之 Carousel 轮播图
实现无缝轮播。
·
Vue 组件封装之 Carousel 轮播图
一、Carousel 轮播图组件
组件说明:
实现无缝轮播。
效果展示:
无缝轮播效果
实现的功能:
- 是否自动轮播,默认为是,可配置;
- 是否显示指示灯,是否显示左右点击按钮,默认为是,可配置。
(左右点击按钮是点击图片区域(移动端)或者鼠标移动到图片区域(PC端)出现) - 指示灯点击轮播,左右按钮点击轮播;
- 左右滑动轮播。
二、使用案例
使用div:
<template>
<el-carousel-img>
<div style="background: pink;font-size:3rem;text-align: center">1</div>
<div style="background: yellow;font-size:3rem;text-align: center">2</div>
</el-carousel-img>
</template>
使用图片:
<template>
<el-carousel-img>
<img :src="carpool" alt="">
<img :src="gold" alt="">
</el-carousel-img>
</template>
<script>
import carpool from '../assets/carpooling.png';
import gold from '../assets/gold-detail.png';
export default {
data(){
return{
carpool,
gold
}
}
}
</script>
三、API 使用指南
属性 | 说明 | 类型 | 默认值 |
---|---|---|---|
height | 轮播图高度,注意,如果设置了指定高度,图片也要设置高度 | String | 200px |
interval | l轮播间隔时间 | Number | 2000ms |
transitionTime | 轮播过度时间,必须小于轮播间隔时间 | Number | 1000ms |
isIndicator | 是否显示指示灯 | Boolean | true |
isHandle | 是否显示左右按钮 | Boolean | true |
autoplay | 是否自动播放 | Boolean | true |
四、源代码
CarouselImg.vue
<template>
<div class="carousel-container" :style="{height:height}"
@mouseenter.stop="handleMouseEnter"
@mouseleave.stop="handleMouseLeave"
>
<div v-if="handleDisplay">
<button
class="carousel-arrow carousel-arrow-left"
@click.stop="throttledArrowClick(controlDisabled[0].label)"
:disabled="controlDisabled[0].disabled"
><i class="arrow-left"></i></button>
<button
class="carousel-arrow carousel-arrow-right"
@click.stop="throttledArrowClick(controlDisabled[1].label)"
:disabled="controlDisabled[1].disabled"
><i class="arrow-right"></i></button>
</div>
<div ref="list" class="carousel-list"
@touchstart="moveStart"
@touchmove="moving"
@touchend="moveEnd"
>
<slot class="carousel-pane"></slot>
</div>
<ul class="carousel-indicator" v-if="isIndicator" ref="indicator">
<li v-for="(item,index) in carouselLength"
@click="setCurrentItem(index)"
:class="[index == (currentIndex-1)?'is-active-item':'','carousel-indicator-item']">
</li>
</ul>
</div>
</template>
<script>
export default {
name: "ElCarouselImg",
data(){
return {
currentIndex:1,//当前索引
carouselLength:0,//实际轮播图个数
timer:null,//定时器
handle:false,//是否显示左右点击按钮
//设置点击状态
controlDisabled:[
{label:'leftBtn',disabled:false},
{label:'rightBtn',disabled:false},
{label:'child',disabled:false},
],
isMoving:false,
start: {
x: 0
},
time:0,//滑动时触摸结束回弹时间。
imgList:null,//轮播图片的父元素
width:window.innerWidth//移动距离
}
},
props:{
interval: {
type: Number,
default: 2000//轮播间隔时间
},
transitionTime:{
type: Number,
default: 1000//轮播过度时间
},
isIndicator: {
type: Boolean,
default: true//是否显示指示灯
},
height: String,//轮播图高度
isHandle:{
type: Boolean,
default: true//是否显示左边点击按钮,默认点击图片并且图片大于1张时显示
},
isAutoplay:{
type: Boolean,
default: true//是否开启自动轮播
}
},
computed: {
handleDisplay() {
return this.isHandle && this.handle && this.carouselLength>1;
},
},
mounted(){
//启动轮播图
this.prepare();
},
created(){
},
methods:{
moveStart(e){
e.stopPropagation();
this.start.x = e.changedTouches[0].pageX;
},
moving(e){
e.stopPropagation();
this.pauseTimer();
var distanceX = e.changedTouches[0].pageX - this.start.x;
this.imgList.style.transform ='translate3d('+ (-this.currentIndex * this.width + distanceX) +'px,0,0)';
this.imgList.style.transition = 'transform 0s';
this.isMoving = true;
},
moveEnd(e){
if(this.isMoving){
e.stopPropagation();
this.time = 300;
var distanceX = e.changedTouches[0].pageX - this.start.x;
if(distanceX<0){
this.currentIndex++ ;
if(this.currentIndex == this.carouselLength+1){
this.criticality(1,undefined,300);
}else {
this.play(300);
}
}else{
this.currentIndex-- ;
if(this.currentIndex == 0){
this.criticality(this.carouselLength,undefined,300);
}else {
this.play(300);
}
};
this.isMoving = false;
this.autoPlay();
}
},
prepare(){
this.imgList = this.$refs.list;
var children = this.imgList.children;
this.carouselLength = children.length;
if(this.carouselLength>1){
this.width = this.imgList.clientWidth;
//首尾各添加一张图片,以便无缝轮播
var firstDom = this.imgList.firstElementChild && this.imgList.firstElementChild.cloneNode(true);
var lastDom = this.imgList.lastElementChild && this.imgList.lastElementChild.cloneNode(true);
if(this.imgList.firstElementChild){
this.imgList.appendChild(firstDom);
this.imgList.insertBefore(lastDom,this.imgList.firstElementChild);
this.imgList.style.transform ='translate3d('+ (-this.width) +'px,0,0)';
}
if(this.isAutoplay){
this.autoPlay();
}
}
},
//停止定时器
pauseTimer(){
if(this.timer){
clearTimeout(this.timer);
this.timer = null;
}
},
handleMouseEnter(){
if(this.isHandle){
this.handle = true;
this.pauseTimer();
}
},
handleMouseLeave(){
if(this.isHandle||this.handle){
this.handle = false;
this.autoPlay();
}
},
throttledArrowClick(dir){
if(dir == 'leftBtn'){
this.currentIndex -- ;
}else {
this.currentIndex ++ ;
};
if(this.currentIndex == 0){
this.criticality(this.carouselLength,this.controlDisabled[0]);
}else if(this.currentIndex == (this.carouselLength+1)){
this.criticality(1,this.controlDisabled[1]);
}else {
this.play();
}
},
//轮播处理逻辑
play(transitionTime){
this.imgList.style.transform ='translate3d('+ (-this.currentIndex * this.width)+'px,0,0)';
if(transitionTime){
this.imgList.style.transition = 'transform '+transitionTime+ 'ms';
}else {
this.imgList.style.transition = 'transform '+this.transitionTime+ 'ms';
}
},
setCurrentItem(index){
//点击指示灯时停止轮播。
this.pauseTimer();
if(this.controlDisabled[2].disabled){
return;
}
//点击第一张时
if(index == 0 && this.currentIndex == (this.carouselLength)){
this.currentIndex++;
this.criticality(1,this.controlDisabled[2]);
}else if(index == (this.carouselLength-1) && this.currentIndex == 1){
this.currentIndex -- ;
this.criticality(this.carouselLength,this.controlDisabled[2]);
}else {
this.currentIndex = index+1;
this.play();
}
},
criticality(boundary,item,transitionTime){
this.play(transitionTime);
this.currentIndex = boundary;
setTimeout(()=>{
this.imgList.style.transform ='translate3d('+ (-this.width*boundary)+'px,0,0)';
this.imgList.style.transition = 'transform 0ms';
},transitionTime?transitionTime:this.transitionTime);
//点击临界值时将点击状态暂停掉以便偷梁换柱
if(item){
var after = new Date().getTime()+1000+100;
if((new Date().getTime())<= after){
item.disabled = true;
setTimeout(()=>{
item.disabled = false;
},after-new Date().getTime())
}
}
},
autoPlay(){
this.timer = setInterval(()=>{
this.currentIndex++;
if(this.currentIndex == this.carouselLength+1){
clearInterval(this.timer);
this.criticality(1);
this.autoPlay();
}else {
this.play();
}
},this.interval);
}
},
beforeDestroy() {
this.pauseTimer();
}
}
</script>
<style>
.carousel-container{
position: relative;
width:100%;
height: 200px;
overflow: hidden;
}
.carousel-indicator{
display: flex;
bottom: 10%;
position: absolute;
z-index: 99;
width: 100%;
justify-content: center;
}
.is-active-item{
opacity: 1!important;
}
.carousel-indicator-item{
margin: 0 5px;
background: #fff;
width: 30px;
height: 3px;
list-style: none;
border-radius: 20px;
opacity: 0.5;
}
.carousel-list{
display: flex;
position: relative;
}
.arrow-left,.arrow-right{
font-family: element-icons;
font-style: normal;
}
.arrow-right:before {
content: "\e6e0"
}
.carousel-list img{
width: 100%;
flex-shrink: 0;
}
.carousel-list div{
width: 100%;
flex-shrink: 0;
overflow: hidden;
}
.arrow-left:before {
content: "\e6de"
}
.carousel-arrow {
border: none;
outline: 0;
padding: 0;
margin: 0;
height: 36px;
width: 36px;
cursor: pointer;
-webkit-transition: .3s;
transition: .3s;
border-radius: 50%;
background-color: rgba(31, 45, 61, .11);
color: #FFF;
position: absolute;
top: 50%;
z-index: 10;
-webkit-transform: translateY(-50%);
transform: translateY(-50%);
text-align: center;
font-size: 12px
}
.carousel-arrow-left{
left: 15px;
}
.carousel-arrow-right{
right: 15px;
}
</style>
更多推荐
已为社区贡献12条内容
所有评论(0)