feat(首页): 使用 Swiper替换 Element UI 轮播组件

- 移除 Element UI 的 el-carousel 组件
-引入 Swiper 库并实现轮播功能
- 优化轮播项的样式和布局
- 添加自定义左右按钮和分页器
- 实现视频自动播放和轮播同步
- 优化轮播切换效果,支持 fade切换
This commit is contained in:
du.meimei
2025-05-24 17:53:08 +08:00
parent db4b68b7c3
commit 9c8d8ee218
27 changed files with 4325 additions and 18063 deletions

22094
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -43,6 +43,7 @@
"shrinkpng": "1.1.0",
"signature_pad": "4.0.3",
"sortablejs": "1.15.0",
"swiper": "^6.8.4",
"three": "0.145.0",
"tinymce": "5.10.7",
"uuid": "8.3.2",

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 315 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 381 KiB

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 202 KiB

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 664 B

After

Width:  |  Height:  |  Size: 458 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 254 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 585 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 273 KiB

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 178 B

After

Width:  |  Height:  |  Size: 148 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 190 B

After

Width:  |  Height:  |  Size: 169 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 B

After

Width:  |  Height:  |  Size: 152 B

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 755 B

After

Width:  |  Height:  |  Size: 464 B

View File

@@ -4,14 +4,14 @@
<p class="fw-bold fs-24 title">简单4步轻松完成你的调研</p>
<p class="desc">创建编辑投放分析让洞察更简单</p>
</div>
<div style="height: 100%">
<el-carousel
:autoplay="true"
:interval="13000"
arrow="always"
indicator-position="none"
style="height: 100%">
<el-carousel-item v-for="(item,index) in operatingList" :key="item" >
<div style="height: 80%">
<div class="swiper-container" ref="swiperContainer">
<div class="swiper-wrapper">
<div
v-for="(item, index) in operatingList"
:key="index"
class="swiper-slide"
>
<div class="flex" style="justify-content: center">
<div style="margin-right: 9%">
<div class="flex-start operating-item" >
@@ -47,33 +47,72 @@
<div>
<video
ref="videoPlayer"
width="720"
height="380"
class="video-player"
width="820"
height="420"
autoplay
muted
playsinline
style="width: 100%;">
<source src="@/assets/img/home/viedeo.mp4" type="video/mp4">
<source :src="getVideo(index)" type="video/mp4">
Your browser does not support the video tag.
</video>
</div>
</div>
</el-carousel-item>
</el-carousel>
</div>
</div>
<!-- 分页器 -->
<div class="swiper-pagination" ref="pagination"></div>
<!-- 自定义左右按钮 -->
<div class="custom-swiper-button-prev" ref="prevBtn" @click="goPre">
<img ref="prevImg" src="@/assets/img/home/kanoicon.png" alt="Previous" />
</div>
<div class="custom-swiper-button-next" ref="nextBtn" @click="goNext">
<img ref="nextImg" src="@/assets/img/home/pkicon.png" alt="Next" />
</div>
</div>
</div>
</div>
</template>
<script setup>
import {ref, onMounted} from 'vue'
import {ref, onMounted, onBeforeUnmount} from 'vue'
import Swiper from 'swiper';
import 'swiper/swiper-bundle.css';
import { useRouter } from 'vue-router';
import { getQueryUserSurvey } from '@/api/home';
import { useStore } from 'vuex';
const router = useRouter();
const emit = defineEmits(['create-survey']);
const operatingList = ref([{
const swiperContainer = ref(null);
const pagination = ref(null);
const prevBtn = ref(null);
const nextBtn = ref(null);
const prevImg = ref(null);
const nextImg = ref(null);
// 🟩 存储 Swiper 实例
let mySwiper = null;
const goPre = () => {
if (mySwiper) {
mySwiper.slidePrev(); // 👈 使用实例方法
}
};
const goNext = () => {
if (mySwiper) {
mySwiper.slideNext(); // 👈 使用实例方法
}
};
const operatingList = ref(
[
{
title: '多种方式',
desc:'快速创建问卷',
descList:[
@@ -136,6 +175,105 @@ const toSurveyInfo = async (item,index) => {
}
}
}
const getVideo = (index) => {
return require(`@/assets/img/home/video${index+1}.mp4`)
}
const addVideoEndedListener =()=> {
const videos = document.querySelectorAll('.video-player');
videos.forEach((video, index) => {
video.addEventListener('ended', () => {
if (index < operatingList.value.length - 1) {
mySwiper.slideNext(); // 自动滑动到下一页
}
});
// // 使用 WeakMap 或 data-* 存储监听器,方便后续移除
// video._onVideoEnd = onVideoEnd;
// video.addEventListener('ended', onVideoEnd);
});
}
/**
* 更新左右图标
* @param currentIndex
*/
const updateButtonImages = (currentIndex) => {
// 获取 next 按钮的 img 元素
const nextImgElement = nextImg.value;
const prevImgElement = prevImg.value;
if (currentIndex === 0) {
prevImg.value.src = require('@/assets/img/home/arrow-dis.png');
nextImg.value.src = require('@/assets/img/home/arrow-act.png');
prevImgElement.style.transform = 'rotate(0deg)';
} else if (currentIndex === 3) {
nextImg.value.src = require('@/assets/img/home/arrow-dis.png');
nextImgElement.style.transform = 'rotate(180deg)';
}else{
// 其他情况恢复默认图片
prevImg.value.src = require('@/assets/img/home/arrow-act.png');
nextImg.value.src = require('@/assets/img/home/arrow-act.png');
prevImgElement.style.transform = 'rotate(180deg)';
nextImgElement.style.transform = 'rotate(0deg)';
}
};
/**
* 自动播放视频
*/
const autoPlayCurrentVideo = () => {
const activeSlide = mySwiper.slides[mySwiper.realIndex];
if (activeSlide) {
const video = activeSlide.querySelector('.video-player');
if (video) {
video.play().catch(err => {
console.warn('视频自动播放失败(可能被浏览器策略阻止)', err);
});
}
}
};
onMounted(() => {
// 🟩 初始化 Swiper 并赋值给 mySwiper
mySwiper = new Swiper(swiperContainer.value, {
loop: false,
autoplay: {
delay: 1300,
},
pagination: {
el: pagination.value,
clickable: true,
},
navigation: {
nextEl: nextBtn.value,
prevEl: prevBtn.value,
},
effect: 'fade',
fadeEffect: {
// crossFade: true, // 启用交叉淡出
},
simulateTouch: false, // 禁止滑动切换
on: {
init: () => {
updateButtonImages(0)
addVideoEndedListener(); // 初始化时添加监听器
},
slideChange: () => {
updateButtonImages(mySwiper.realIndex)
autoPlayCurrentVideo(); // 每次切换时播放当前页视频
},
},
});
});
// 在组件卸载时清理监听器
onBeforeUnmount(() => {
const videos = document.querySelectorAll('.video-player');
videos.forEach(video => {
if (video._onVideoEnd) {
video.removeEventListener('ended', video._onVideoEnd);
}
});
});
</script>
<style scoped lang="scss">
@@ -154,9 +292,8 @@ li{
}
.operating-container{
margin-top: 20px;
margin-bottom: 60px;
min-height: 500px;
height: 500px;
min-height: 600px;
height: 600px;
.top{
margin-bottom: 40px;
}
@@ -193,6 +330,7 @@ li{
font-size: 24px;
font-weight: bold;
margin-left: 20px;
white-space: nowrap;
}
}
.desc-item{
@@ -237,4 +375,55 @@ li{
:deep(.el-carousel__container) {
height: 100%;
}
.swiper-container {
height: 100%;
width: 95%;
margin: 0 auto;
}
.swiper-slide {
//display: flex;
//align-items: center;
//justify-content: center;
font-size: 24px;
height: 100%;
//position: absolute; /* 必须设置为绝对定位才能实现 fade 切换 */
width: 100%;
//top: 0;
//left: 0;
//transition: opacity 1s ease;
}
/* 自定义按钮样式 */
.custom-swiper-button-prev,
.custom-swiper-button-next {
position: absolute;
top: 50%;
transform: translateY(-50%);
z-index: 10;
cursor: pointer;
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
//background-color: rgba(0, 0, 0, 0.5);
border-radius: 50%;
}
.custom-swiper-button-prev img,
.custom-swiper-button-next img {
width: 30px;
height: 30px;
filter: brightness(100%);
}
.custom-swiper-button-prev {
left: 0;
}
.custom-swiper-button-next {
right: 0;
}
</style>