二次封装el-carousel

我们创建了一个名为MyCarousel的组件,它接受el-carousel的一些常用属性作为props,并默认提供了一些值。我们还通过setup函数返回了所有props,以便它们可以在模板中被使用。

1.MyCarousel.vue组件

<!-- 轮播图片 -->
<template>
	<div class="carousel" :class="[{ twoBox: isTwo }, { elseBox: !isTwo }]">
		<el-carousel
			loop
			indicator-position="outside"
			class="carouselBox"
			:arrow="carouselListData.length === 1 ? 'never' : 'hover'"
			@change="changeItem"
			ref="carouse"
		>
			<el-carousel-item
				:width="props.width + 'px'"
				v-for="(item, index) in carouselListData"
				:key="index"
				@click="goHomepage(item)"
			>
				<img
					:src="item.imageUrl"
					:style="{
						width: props.widthImage + '%',
						height: props.heightImage + '%',
						cursor: item.posterLink || props.activeTab ? 'pointer' : ''
					}"
					alt="轮播图图片"
				/>
			</el-carousel-item>
		</el-carousel>
	</div>
</template>

<!-- 轮播图 -->
<script setup lang="ts" name="CustomCarousel">
	import { QueryPosterInfoListOutput } from '@/api/home/types';
	import _ from 'lodash';

	const isTwo = ref(false); // 判断是不是两条数据
	const carouse = ref();
	const emit = defineEmits({ clickGoPage: null, changeItem: null });
	const props = defineProps({
		// 轮播图宽度
		width: {
			type: Number,
			default: 0
		},
		// 轮播图高度
		height: {
			type: String,
			default: '400'
		},
		type: {
			type: String,
			default: 'card'
		},
		// 相邻两张图片切换的间隔时间
		interval: {
			type: Number,
			default: 4000
		},
		//图片宽
		widthImage: {
			type: Number,
			default: 100
		},
		//图片高
		heightImage: {
			type: Number,
			default: 100
		},
		// 轮播图路径数组
		carouselList: {
			type: Array<QueryPosterInfoListOutput>,
			default: () => []
		},
        // 点击不同的tab切换对应的轮播图
		activeTab: {
			type: Number,
			default: 0
		}
	});
	const activeIndex = ref(0);
	const carouselListData = ref<QueryPosterInfoListOutput[]>([]);

	watch(
		() => props.carouselList,
		(newVal) => {
			fu(newVal);
		}
	);
	// 针对阶梯套餐的特殊处理
	watch(
		() => props.activeTab,
		(newVal) => {
			// console.log(activeIndex.value, 'newVal======', newVal);
			// 因为是element-ui组件的一个bug两张图片的需要单独特殊处理,目的是避免切换tab的时候,轮播图切换到上一张,轮播方向错误
			if (isTwo.value) {
				// 上一个的tab值
				const prev = carouselListData.value[activeIndex.value];
				// 如果上一个的值和当前点击的的一样,不做改变
				if (prev.id === newVal) {
					return;
				} else {
					let index = _.findIndex(carouselListData.value, (item, i) => {
						return item.id === newVal && i > activeIndex.value;
					});
					// 如果是最后一张图的时候需要回来到第一张图片
					if (index === -1) {
						index = 0;
					}
					// 重新设置选中的默认值
					carouse.value.setActiveItem(index);
				}
			} else {
				const index = _.findIndex(carouselListData.value, (item) => {
					return item.id === newVal;
				});
				carouse.value.setActiveItem(index);
			}
		}
	);

	// 点击进入链接,发起方法调用
	const goHomepage = (value: QueryPosterInfoListOutput) => {
		emit('clickGoPage', value);
		if (value.posterLink) {
			window.open(value.posterLink, '_blank');
		}
	};
    
	const changeItem = (val: any) => {
		const value = carouselListData.value[val];
		activeIndex.value = val;
		// console.log('index-----------', val);
		emit('changeItem', value);
	};

	onMounted(() => {
		fu(props.carouselList);
	});

	/**
	 * 重新处理,el-carousel-item数量为2时,组件循环方向一左一右的问题
	 *
	 * 思路:如果为2时,复制一次,使其成为长度length为4的数组,然后将Carousel组件的indicators(下标显示器)多复制的给隐藏(原本长度为2,现在为4,就隐藏第3个和第4个)
	 * @param data
	 */
	const fu = (data: QueryPosterInfoListOutput[]) => {
		if (data) {
			if (data.length === 2) {
				isTwo.value = true;
				//将2条数据复制一份为4条数据
				carouselListData.value = data.concat(data);
			} else {
				isTwo.value = false;
				//其他时候正常赋值
				carouselListData.value = data;
			}
		}
	};
</script>

<style scoped lang="scss">
	.twoBox {
		width: 100%;
		height: 100%;

		.carouselBox {
			width: 100%;

			//将复制出来的数据的下标隐藏
			:deep(.el-carousel__indicators) {
				& > li:nth-child(3),
				& > li:nth-child(4) {
					display: none;
				}
			}
		}
	}

	.elseBox {
		width: 100%;
		height: 100%;

		.carouselBox {
			width: 100%;
		}
	}
	.carousel {
		:deep {
			.el-carousel__indicators--outside .is-active button {
				background-color: var(--el-color-primary);
				width: 20px;
				height: 3px;
			}
			.el-carousel__indicators--outside button {
				// background-color: #e1e1e1;
				width: 9px;
			}
			.el-carousel__arrow {
				background-color: #8b8b8b;
			}
			.el-carousel__arrow--left {
				left: 16.1%;
				opacity: 40%;
			}
			.el-carousel__arrow--right {
				right: 16.1%;
				opacity: 40%;
			}
			.el-carousel__arrow--right:active,
			.el-carousel__arrow--left:active {
				opacity: 80%;
			}
			.el-carousel__container {
				margin-bottom: 7px;
				position: relative;
				width: 100%;
				height: auto;
				// aspect-ratio: 1440/600
				img {
					position: absolute;
					top: 0;
					left: 0;
					width: 100%;
					height: 100%;
				}
			}
		}
	}
</style>

2.使用:

基础用法:

<template>
    <my-carousel
        v-if="bannerImgsList.length"
	    :height="'582'"
	    :carouselList="bannerImgsList"
	     @clickGoPage="clickGoPage"
	/>
</template>

<script setup lang="ts">
import { QueryPosterInfoListOutput } from '@/api/home/types';
const bannerImgsList = ref<QueryPosterInfoListOutput[]>([]);

const clickGoPage = (value: IcarouselList) => {
		console.log('=====', value);
		// router.push("/home");
};
</script>

 需要结合tab来动态联动的用法:

<template>
	<div class="step-package margin-top40" v-if="ladderPackageList && ladderPackageList.length">
		<!-- 切换的tab -->
		<div class="flex-center margin-top20">
			<div
				v-for="item in ladderPackageList"
				:key="item.id"
				class="step-package-tabs"
				:class="{ 'step-package-tabs-active': activeTab == item.id }"
			>
				<el-button class="img-button" @click="clickSelectTab(item)">
					{{ item.posterName }}
				</el-button>
			</div>
		</div>
		<!-- 轮播图 -->
		<div class="margin-top30 step-carousel">
			<my-carousel
				:height="'422'"
				:width="1000"
				:carouselList="ladderPackageList"
				@changeItem="changeItem"
				@clickGoPage="clickGoPage"
				:activeTab="activeTab"
			/>
		</div>
	</div>
</template>
<script setup lang="ts">
	import { ref } from 'vue'
	import { useRouter } from 'vue-router';
	import { queryFrontLadderPackageFront } from '@/api/ladderPackage';
	import { QueryLadderPackageOutput } from '@/api/ladderPackage/types';
	const router = useRouter();

	const ladderPackageList = ref();
	const activeTab = ref<number>(0);

	onMounted(() => {
		getData ();
	});
	const getData = async () => {
		const result = await 接口;
		if (result && result.length) {
			ladderPackageList.value = result;
			activeTab.value = result[0].id;
		}
	};

	const clickSelectTab = (item: QueryLadderPackageOutput) => {
		activeTab.value = item.id;
	};

	const clickGoPage = (val: any) => {
		console.log('val', val);
	};
	const changeItem = (val: any) => {
		activeTab.value = val.id;
	};
</script>
<style lang="scss" scoped>
	.step-package {
		height: 100%;
		width: 100%;
		.step-package-content {
			width: 70%;
			margin: 0 auto;
		}
		.step-carousel {
			:deep {
				.el-carousel__container {
					aspect-ratio: 1440/420;
				}
			}
		}
		.step-package-tabs {
			margin: 0 3em;
			cursor: pointer;
			border-radius: 16px;
			.img-button {
				border: 0;
				border-radius: 16px;
			}
		}
		.step-package-tabs-active {
			margin: 0 3em;
			background-color: var(--el-color-primary);
			color: #fff;
			.img-button {
				background-color: var(--el-color-primary);
				border-color: var(--el-color-primary);
				color: #fff;
			}
		}
	}
</style>

3.效果图:

最后,同个点击上面的tab切换到不同的图片上,同理,切换不同的轮播图,上面的tab也会跟着动,双向的联动。 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值