uniapp头像堆叠轮播(仿拼多多)

172 阅读2分钟

参考了uniapp插件市场的头像轮播实现,在其基础上优化了实现效果

<template>
	<view class="avatar-banner" :style="[boxBaseSyle()]">
		<image
			v-for="(avatar, index) in list"
			:key="avatar.id"
			:src="avatar.url"
			class="absolute"
			:style="[itemBaseSyle(), itemSyle(index, avatar)]"
		>
		</image>
	</view>
</template>

<script>
export default {
	name: "AvatarBanner",
	props: {
		urls: {
			type: Array,
			default: () => {
				return [];
			},
		},
		interval: {
			type: Number,
			default: 1500,
			desc: "轮播间隔时间",
		},
		width: {
			type: Number,
			default: 40,
		},
		height: {
			type: Number,
			default: 40,
		},
		overlap: {
			type: Number,
			default: 20,
			desc: "重叠的部分",
		},
		showNumber: {
			type: Number,
			default: 5,
			desc: "展示数量,实际展示少一个",
		},
	},
	data() {
		return {
			imageUrls: [
				`./static/image/insurance/term2/avatar-1@2x.png`,
				`./static/image/insurance/term2/avatar-2@2x.png`,
				`./static/image/insurance/term2/avatar-3@2x.png`,
				`./static/image/insurance/term2/avatar-4@2x.png`,
				`./static/image/insurance/term2/avatar-5@2x.png`,
				`./static/image/insurance/term2/avatar-6@2x.png`,
				`./static/image/insurance/term2/avatar-7@2x.png`,
				`./static/image/insurance/term2/avatar-8@2x.png`,
				`./static/image/insurance/term2/avatar-9@2x.png`,
				`./static/image/insurance/term2/avatar-10@2x.png`,
				`./static/image/insurance/term2/avatar-11@2x.png`,
			],
			list: [],
			tempList: [],
			intervalTimer: null,
			curLastIndex: 0,
		};
	},
	computed: {
		marginLeft() {
			return this.width - this.overlap;
		},
	},
	watch: {},
	mounted() {
		this.stop();
		this.handleUrls();
	},
	beforeDestroy() {
		this.stop();
	},
	onUnload() {
		this.stop();
	},
	methods: {
		handleUrls(val = []) {
			const defaultList = this.imageUrls;
			const urls = !val || !val.length ? defaultList : val;
			this.tempList = urls;
			const length = urls.length;
			const len = this.showNumber > length ? length : this.showNumber;
			const tempList = urls.slice(0, len).map((item, index) => {
				const url = item;
				const order = index + 1;
				return {
					url,
					order: order,
					id: `avatar-${order}`,
				};
			});
			this.list = tempList;
			this.curLastIndex = this.showNumber;
			this.start();
		},
		itemSyle(index, item) {
			const total = this.list.length;
			const left = this.marginLeft;
			const style = {
				"z-index": Math.abs(item.order - total),
				transition: `${this.interval / 1000}s`,
				transform: `translateX(-${
					(item.order - 1) * left
				}rpx) scale(1)`,
			};
			// 缩小中
			if (item.order == 0) {
				style.transform = `translateX(0) scale(0)`;
			}
			// 位移中 移动到末尾
			if (item.order == this.showNumber) {
				style.transform = ` translateX(0) scale(0)`;
			}
			// 进行缩放和位移状态的改变
			this.nextState(item);
			return style;
		},
		// 进行缩放和位移 状态 的改变 不具体执行缩放
		nextState(item) {
			const total = this.list.length;
			if (item.order == 0) {
				const timer = setTimeout(() => {
					// 300 后缩放结束 开始移动到末尾
					item.order = total;
					clearTimeout(timer);
				}, 250);
			}
		},
		itemBaseSyle() {
			return { width: this.width + "rpx", height: this.height + "rpx" };
		},
		boxBaseSyle() {
			const len = this.list.length;
			return {
				width: len * this.width - (len - 1) * this.overlap + "rpx",
				height: this.height + "rpx",
				marginLeft: "-" + this.overlap + "rpx",
			};
		},
		start() {
			this.intervalTimer = setInterval(() => {
				this.forwardMove();
			}, this.interval); // 可以根据需要调整间隔时间
		},
		stop() {
			clearInterval(this.intervalTimer);
			this.intervalTimer = null;
		},
		/**
		 * 向前移动
		 */
		forwardMove() {
			// 第一条数据
			this.list.forEach((item, index) => {
				// 最后一条数据
				if (item.order == 1) {
					setTimeout(() => {
						item.url = this.tempList[this.curLastIndex];
					}, 500);
				}
				item.order--;
			});
			if (this.curLastIndex === this.tempList.length - 1) {
				this.curLastIndex = 1;
			} else {
				this.curLastIndex++;
			}
		},
	},
};
</script>

<style lang="scss" scoped>
.avatar-banner {
	overflow: hidden;
	width: 100%;
	position: relative;
}
.absolute {
	position: absolute;
	border-radius: 50%;
	right: 0;
}
</style>

由于要动态替换图片进行轮播,动画效果使用css和js的定时器效果实现 目前存在问题:手机端页面切入后台,由于使用了定时器效果,切回来的时候轮播动画加速了