我们创建了一个名为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也会跟着动,双向的联动。