奇葩轮播banner图组件

593 阅读4分钟

<template>
  <div class="home">
    <div class="step-2">
      <swiper :arrayList="list">
        <img slot-scope="props" :src="props.data.src" alt="" />
      </swiper>
    </div>
  </div>
</template>

<script>
import swiper from "./banner"
export default {
  name: 'app',
  data () {
    return {
      list: [{
        msg:1,
        src: require('@/assets/1.jpg')
      }, {
         msg:2,
        src: require('@/assets/2.jpg')
      }, {
        msg:3,
        src: require('@/assets/3.jpg')
      }, {
      	msg:4,
        src: require('@/assets/4.jpg')
      },
      {
      	msg:5,
        src: require('@/assets/4.jpg')
      },{
      	msg:6,
        src: require('@/assets/4.jpg')
      }
      
      ]
    }
  },
  components: {
    swiper
  }
}
</script>

<style>
  * {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
  }
  img {
    display: block;
    width: 100%;
  }
  .step-2 {
    position: relative;
  }
</style>
<template>
	<div class="carousel_cpmponent">
		<section class="carousel_content">
			<div ref="swiper" class="carousel_swiper" @touchstart="touchstart" @touchmove="touchmove" @touchend="touchend">
				<div class="carousel_swiper_item" ref="container" v-for="(item, i) of list" :key="i" :class="{active:index==i}">
					{{item.msg}}
				</div>
			</div>
		</section>
		<div class="carousel_indicator">
			<div v-for="(tag, i) of arrayList.length" 
				:class="{active:item==i}" 
				class="carousel-indicator-item" :key="i" />
	        </div>
	    </div>
	</div>
</template>

<script>
	export default {
		name: 'swiper',
		props: {
			autoPlay: {
				default: true // 是否支持自动播放
			},
			duration: {
				default: 300 // 滚动一次过度的时间
			},
			delayed: {
				default: 2500 // 多久滚动一次
			},
			arrayList: Array, // 这个是数据
			padding: {
				type: Array,
				default: function() {
					return [10, 20]
				}
			}
		},
		data() {
			return {
				width: 0,
				timer:0,
				touching: false,
				dom: {},
				diff: 0, // 目前所在位置
				startX: 0, // 手指触到屏幕上的x轴坐标
				moveX: 0, // 手指滑动后 手指所在的x轴坐标
				index: 0,//轮播图当前index
			}
		},
		computed: {
			item(){
				return this.list[this.index]&&this.list[this.index].tag;
			},
			paddingpx() {
				return this.padding[0] + this.padding[1]
			},
			translate() {
				return -this.index*(this.width + this.paddingpx)
			},
			list() {
				this.arrayList.map((item,index)=>{return item.tag=index});
				return [...this.arrayList.slice(-2), ...this.arrayList, ...this.arrayList.slice(0, 2)]

			}
		},
		created() {
			 this.index=2;
		},
		mounted() {
			setTimeout(() => {
				this.starDom();
				this.Transition(0);
				this.Translate(this.translate);
				this.autoPlay&&this.AutoPlay();
			}, 50);
			
			this.$refs.swiper.addEventListener("transitionend",()=>{
				console.log("结束");
				this.touching=false;
				if(this.index-1==this.arrayList.length){
						this.index=1;
						this.Transition(0);
					    this.Translate(this.translate);
				}
				
				if(this.index==0){
					this.index=this.arrayList.length;
					this.Transition(0);
				    this.Translate(this.translate);
				}
			})
		},
		methods: {
			starDom() { // 初始化数据 以及获取必要的数据
				this.width = document.documentElement.clientWidth * 0.8;
				this.$refs.container.forEach(item => {
					item.style.width = `${this.width}px`;
					item.style.margin = `0px ${this.padding[1]}px 0px ${this.padding[0]}px`
				})
				this.dom = this.$refs.swiper.style;
			},
			touchstart(e) {
				if(this.touching){
					return false;
				}
				this.startX = e.changedTouches[0].clientX;
				this.pauseAutoPlay();
			},
			touchmove(e) {
				if(this.touching){
					return false;
				}
				this.moveX = e.changedTouches[0].clientX;
				this.diff = this.moveX - this.startX;
				this.Transition(0);
				this.Translate(this.translate + this.diff);
				this.pauseAutoPlay();
			},
			touchend() {
				this.touching=true;
				if(this.diff > 30) { //右滑
					this.Prev();
				} else if(this.diff < -30) { //左滑
					this.Next();
				} else {
					this.Transition(this.duration);
					this.Translate(this.translate);
				}
				this.autoPlay&&this.AutoPlay();
				 
			},
			Transition(time) {
				this.dom.transition = time + 'ms';
				this.dom.webkitTransition = time + 'ms';
			},
			Translate(num) {
				this.dom.transform = `translate3d(${num}px, 0, 0)`;
				this.dom.transform = `webkikTranslate3d(${num}px, 0, 0)`;
			},
			Prev(){
				this.index--;
				this.Transition(this.duration);
				this.Translate(this.translate);
			},
			Next(){
				this.index++;
				this.Transition(this.duration);
				this.Translate(this.translate);
			},
			AutoPlay(){
				this.timer=setInterval(()=>{
					this.Next();
				},this.delayed)
			},
			pauseAutoPlay(){
				clearInterval(this.timer);
			}
		}

	}
</script>

<style scoped="scoped" lang="less">
	.carousel_cpmponent {
		width: 100%;
		height: 100%;
		.carousel_content {
			position: relative;
			z-index: 1;
			width: 100%;
			height: 100%;
			overflow: hidden;
			.carousel_swiper {
				width: 100%;
				height: 100%;
				display: -webkit-box;
				transition-duration: 0s linear;
				.carousel_swiper_item {
					width: 100%;
					height: 100px;
					line-height: 100px;
					text-align: center;
					font-size: 24px;
					background: green;
					&:nth-child(2n){
						background: gold;
					}
				}
			}
		}
		.carousel_indicator {
			position: absolute;
			bottom: 8px;
			width: 100%;
			height: 10px;
			text-align: center;
			background: 0 0;
			z-index: 1;
			display: flex;
			justify-content: center;
			.carousel-indicator-item {
				width: 8px;
				height: 8px;
				margin: 1px 7px;
				cursor: pointer;
				border-radius: 100%;
				background: white;
				&.active{
					background: red;
				}
			}
		}
	}
</style>

Swiper

<template>
  <div class="home">
    <swiper :data="list" :padding="30" :margin="5">
      <img class="step-1" slot-scope="props" :src="props.data.src" alt="" />
    </swiper>
    <div class="hr">-----分割线-----</div>
    <div class="step-2" style="display: none;">
      <swiper :data="list">
        <img slot-scope="props" :src="props.data.src" alt="" />
      </swiper>
    </div>
    <div class="hr">-----分割线-----</div>
  </div>
</template>

<script>
import swiper from "./swiper"
export default {
  name: 'app',
  data () {
    return {
      list: [{
        src: require('@/assets/1.jpg')
      }, {
        src: require('@/assets/2.jpg')
      }, {
        src: require('@/assets/3.jpg')
      }, {
        src: require('@/assets/4.jpg')
      }]
    }
  },
  components: {
    swiper
  }
}
</script>

<style>
  * {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
  }
  img {
    display: block;
    width: 100%;
  }
  .step-1 {
    border-radius: 10px;
  }
  .hr {
    height: 40px;
    line-height: 40px;
    font-size: 14px;
    text-align: center;
  }
  .step-2 {
    position: relative;
  }
  .step-2 .carousel_show_bgcolor {
    background-color: rgb(133, 224, 103);
  }
</style>
<template>
	<div class="carousel_cpmponent" 
		@touchmove="preventDefault">
		<section class="carousel_content">
			<div ref="swiper" 
				class="carousel_swiper" 
				@touchstart="touchstart" 
				@touchmove="touchmove" 
				@touchend="touchend">
				<div class="carousel_swiper_item" 
					   ref="container" 
					   v-for="(item, i) of list" :key="i"
					   :index="i"
					   :style="{padding: `0 ${margin / 2}px`}">
					<slot :data="item" :index="i" />
				</div>
			</div>
		</section>
		<div v-if="!crevice" 
			class="carousel_indicator">
			<div v-for="(tag, i) of list.length - 2 * infinite" 
				:class="{ carousel_show_bgcolor: index - 1 + !infinite === i }" 
				class="carousel-indicator-item" :key="i" />
		</div>
	</div>
</template>

<script>
	export default {
		name: 'swiper',
		props: {
			autoPlay: {
				default: true // 是否支持自动播放
			},
			duration: {
				default: 500 // 滚动一次需要的时间
			},
			delayed: {
				default: 250000 // 多久滚动一次
			},
			data: Array, // 这个是数据
			infinite: {
				default: true // 是否可以无限轮播
			},
			padding: {
				default: 0 // 每一个轮播大小控制 = 页面整体宽度 - 此项设置
			},
			margin: {
				default: 0 // 每一个轮播和另一个轮播之间的距离
			}
		},
		data() {
			return {
				width: 0,
				auto: true,
				slideing: true,
				timer1: '',
				dom: {},
				position: 0, // 目前所在位置
				startX: 0, // 手指触到屏幕上的x轴坐标
				moveX: 0, // 手指滑动后 手指所在的x轴坐标
				index: 0
			}
		},
		computed: {
			crevice() {
				if(this.data.length < 3) {
					return false
				}
				return !!this.margin
			},
			list() {
				return this.infinite ? [...this.data.slice(-1), ...this.data, ...this.data.slice(0, 1)] : 
				                       this.data
			}
		},
		created() {
			this.index = +this.infinite
		},
		mounted() {
			setTimeout(() => {
				this.starDom()
				this.dom.webkitTransition = `translate3d(${this.infinite ? this.width * (-this.crevice - 1) + this.crevice * this.padding / 2 : 0}px, 0px, 0px)`
				this.dom.transform = `translate3d(${this.infinite ? this.width * (-this.crevice - 1) + this.crevice * this.padding / 2 : 0}px, 0px, 0px)`
				this.autoPlay && this.infinite && this.setTime()
			}, 50)
		},
		methods: {
			starDom() { // 初始化数据 以及获取必要的数据
				this.width = document.documentElement.clientWidth - this.crevice * this.padding
				this.$refs.container.forEach(item => {
					item.style.width = `${this.width}px`
				})
				this.dom = this.$refs.swiper.style
			},
			touchstart(e) {
				if(this.slideing) {
					this.clearTimeOut()
					this.dom.transition = '0s'
					this.dom.webkitTransition = '0s'
					this.position = this.getTransform()
					this.startX = e.touches[e.touches.length - 1].clientX
				}
			},
			touchmove(e) {
				if(this.slideing && this.startX !== -1) {
					this.clearTimeOut()
					let moveX = e.touches[e.touches.length - 1].clientX - this.startX
					if(this.isTouchmove(moveX)) {
						this.moveX = moveX
						this.setTranslate(this.moveX + this.position)
					}
				}
			},
			touchend() {
				this.clearTimeOut()
				this.setTranslate(this.moveX + this.position)
				if(this.moveX > 0 && this.moveX / this.width > 0.2) {
					this.index--
				}
				if(this.moveX < 0 && this.moveX / -this.width > 0.2) {
					this.index++
				}
				this.move('touch')
			},
			isTouchmove(moveX) {
				return this.infinite ? true : (moveX + this.position <= 0 && moveX + this.position > (this.list.length - 1) * -this.width)
			},
			setTranslate(d) {
				if('transform' in document.documentElement.style) {
					this.transform(d)
				} else {
					this.webkitTransform(d)
				}
			},
			transform(d) {
				this.dom.transform = `translate3d(${d + this.crevice * this.padding / 2}px, 0, 0)`
				this.dom.transform = `webkikTranslate3d(${d + this.crevice * this.padding / 2}px, 0, 0)`
			},
			webkitTransform(d) {
				this.dom.webkitTransform = `translate3d(${d + this.crevice * this.padding / 2}px, 0, 0)`
				this.dom.webkitTransform = `webkikTranslate3d(${d + this.crevice * this.padding / 2}px, 0, 0)`
			},
			getTransform() { // 获取当前轮播的偏移量
				if('transform' in document.documentElement.style) {
					let position = this.dom.transform
					position = position.substring(12)
					position = position.match(/(\S*)px/)[1]
					return Number(position)
				} else {
					return this.index * -1 * this.width + this.crevice * this.padding / 2
				}
			},
			preventDefault(e) {
				e.preventDefault()
			},
			move(type) {
				this.slideing = false
				this.dom.transition = type === 'touch' ? '250ms' : this.duration + 'ms'
				this.dom.webkitTransition = type === 'touch' ? '250ms' : this.duration + 'ms'
				this.setTranslate(this.index * -1 * this.width)
				this.moveX = 0
				this.startX = -1 // 保证下次重新赋值
				this.autoPlay && this.infinite && this.setTime()
				let timeDuration = type === 'touch' ? '250' : this.duration
				this.infinite && setTimeout(() => {
					this.dom.transition = '0s'
					this.dom.webkitTransition = '0s'
					if(this.index === this.list.length - this.crevice - 1) {
						this.index = this.crevice + 1
						this.setTranslate(this.index * -1 * this.width)
					}
					if(this.index === +this.crevice) {
						this.index = this.list.length - this.crevice - 2
						this.setTranslate(this.index * -1 * this.width)
					}
					this.auto = true
					this.slideing = true
				}, timeDuration)
				if(!this.infinite) {
					this.auto = true
					this.slideing = true
				}
			},
			setTime() { // 设置轮询定时器
				this.timer1 = window.setTimeout(() => {
					if(this.auto) {
						this.index++
							this.move()
					} else {
						window.clearTimeout(this.timer1)
					}
				}, this.delayed)
			},
			clearTimeOut() { // 取消轮询定时器
				this.auto = false
				window.clearTimeout(this.timer1)
			}
		},
		activated() {
			this.autoPlay && this.infinite && this.setTime()
		},
		deactivated() {
			window.clearTimeout(this.timer1)
		},
		beforeDestroy() {
			window.clearTimeout(this.timer1)
		}
	}
</script>

<style scoped="scoped" lang="less">
	.carousel_cpmponent {
		width: 100%;
		height: 100%;
		.carousel_content {
			position: relative;
			z-index: 1;
			width: 100%;
			height: 100%;
			overflow: hidden;
			.carousel_swiper {
				width: 100%;
				height: 100%;
				display: -webkit-box;
				transition-duration: 0s linear;
				.carousel_swiper_item {
					width: 100%;
					height: 100%;
				}
			}
		}
		.carousel_indicator {
			position: absolute;
			bottom: 8px;
			width: 100%;
			text-align: center;
			background: 0 0;
			z-index: 1;
			.carousel-indicator-item {
				display: inline-block;
				width: 8px;
				height: 8px;
				margin: 1px 7px;
				cursor: pointer;
				border-radius: 100%;
				background: #aaa;
			}
		}
	}
</style>