vue 实现banner轮播,衔接滚动

769 阅读1分钟

主要用css控制元素位置,展示的内容脱离文档流后,设置当前元素的前、中、后,三个元素的位置。

11.gif

遇到的问题:
  • 需要存上一个展示的index;用于设置过度时的动画。
  • transition动画时间属性只能设置在切换时的前、后;两个属性内。不然会出现调整元素位置的时候有明细的过度动画。
  • 控制transform: translateX(px)位置时,需要判断是否第一个和最后一个元素,单独处理;其他的元素正常横排就行;

贴上代码组件,目前只完成了基本功能,可以自行修改,比如增加鼠标指向时间,左右切换的节流等等:

<template>
	<div class="banner">
		<div class="img-box">
			<div
				v-for="(item, index) in banner"
				:key="index"
				class="img-item"
				:class="{ active: bannerIndex === index || bannerIndex2 === index }"
				:style="bannerStyle(index)"
			>
				{{ index }}
			</div>
		</div>
		<div class="arrows">
			<div class="left" @click="bannerLeft">&lt;</div>
			<div class="right" @click="bannerRight">&gt;</div>
		</div>
		<div class="dots">
			<span
				v-for="(item, index) in banner"
				:key="index"
				:class="{ active: index === bannerIndex }"
				@click="onClickDot(index)"
			></span>
		</div>
	</div>
</template>
<script>
export default {
	data() {
		return {
			banner: 6,
			bannerIndex: 0,
			bannerIndex2: 0,
			t: null,
		};
	},
	mounted() {
		// this.scrollBanner();
	},
	methods: {
		scrollBanner() {
			this.t && clearInterval(this.t);
			this.t = setInterval(() => {
				this.bannerRight();
			}, 3000);
		},
		bannerStyle(index) {
			const { bannerIndex, banner } = this;
			const base = 500;
			let w = 0;
			if (bannerIndex === index) {
				w = 0;
			}
			// 最后一个index,且bannerIndex=0时
			else if (bannerIndex === banner - 1 && index === 0) {
				w = base;
			}
			// 第一个index,且bannerIndex=最后一个时
			else if (bannerIndex === 0 && index === banner - 1) {
				w = -base;
			} else {
				w = base * (index - bannerIndex);
			}
			return `transform: translateX(${w}px);`;
		},
		bannerLeft() {
			this.bannerIndex2 = this.bannerIndex;
			if (this.bannerIndex === 0) {
				this.bannerIndex = this.banner - 1;
			} else {
				this.bannerIndex -= 1;
			}
		},
		bannerRight() {
			this.bannerIndex2 = this.bannerIndex;
			if (this.bannerIndex === this.banner - 1) {
				this.bannerIndex = 0;
			} else {
				this.bannerIndex += 1;
			}
		},
		onClickDot(index) {
			this.bannerIndex2 = this.bannerIndex;
			this.bannerIndex = index;
		},
	},
};
</script>
<style scoped>
.banner {
	width: 500px;
	height: 300px;
	overflow: hidden;
	background: #f2f2f2;
	position: relative;
}
.banner .img-box {
	width: 500px;
	height: 300px;
}
.banner .img-box .img-item {
	width: 100%;
	height: 100%;
	line-height: 100%;
	background: #d3dce6;
	display: flex;
	align-items: center;
	justify-content: center;
	position: absolute;
	top: 0;
	left: 0;
	z-index: 1;
}
.banner .img-box .img-item.active {
	z-index: 2;
	transition: 1s;
}

.arrows {
	display: flex;
	align-items: center;
	justify-content: space-between;
	position: absolute;
	top: 50%;
	left: 0;
	width: 100%;
	z-index: 9;
	padding: 0 10px;
	box-sizing: border-box;
	transform: translateY(-50%);
}
.arrows div {
	width: 30px;
	height: 30px;
	background: rgba(0, 0, 0, 0.1);
	color: #fff;
	font-size: 20px;
	line-height: 30px;
	border-radius: 50%;
	text-align: center;
	cursor: pointer;
}

.dots {
	position: absolute;
	bottom: 10px;
	left: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 100%;
	z-index: 9;
}
.dots span {
	width: 10px;
	height: 10px;
	background: rgba(255, 255, 255, 0.4);
	border-radius: 50%;
	cursor: pointer;
	margin: 0 10px;
}
.dots span.active {
	background: #fff;
}
</style>