功能:

  • 自动循环播放(到达末尾后回到第一张)、可设置切换间隔时间(interval属性)

  • 左右导航按钮(可自定义显示/隐藏)

  • 点击底部指示器跳转到指定幻灯片、且位置可调(轮播图内部/外部)

  • 鼠标拖拽滑动(PC端)

  • 触摸滑动(移动端适配)

  • 支持暂停/继续自动播放(autoPlay控制)

  • 用户交互(拖拽/点击按钮)时自动暂停轮播

  • 点击幻灯片可跳转页面(这里是跳转到详情)

封装好了,直接用就可以:components/Carousel.vue:

<template><div class="carousel-container"><!-- 左侧导航按钮 --><button class="nav-button prev" @click="prevSlide" v-if="showNavButtons">‹</button><div class="carousel-viewport" ref="viewport"@mousedown="startDrag"@mousemove="handleDrag"@mouseup="endDrag"@mouseleave="endDrag"@touchstart="startDrag"@touchmove="handleDrag"@touchend="endDrag"><div class="carousel-track" :style="trackStyle"><div class="slide" v-for="(item, index) in items" :key="item.id"@click="handleSlideClick(index)"><img :src="item.cover" :alt="item.title"><div class="slide-title" :class="{ 'active': currentIndex === index }">{{ item.categoryTag }}</div></div></div></div><!-- 右侧导航按钮 --><button class="nav-button next" @click="nextSlide" v-if="showNavButtons">›</button><div class="indicators" :class="{ 'inside': indicatorsInside }"><span v-for="(item, index) in items" :key="item.id":class="{ 'active': currentIndex === index }"@click="goToSlide(index)"></span></div><!-- 标题和摘要显示区域 --><div class="carousel-caption"><div class="carousel-title">{{ currentItem.title }}</div><div class="carousel-summary">{{ currentItem.summary }}</div></div></div>
</template><script setup>
import { ref, computed, onMounted, onBeforeUnmount, watch } from 'vue';const props = defineProps({items: {  // 父组件传过来的数据,下面会有模拟数据type: Array,required: true,default: () => []},interval: { // 控制自动轮播的切换时间间隔type: Number,default: 3000},autoPlay: { // 是否自动切换type: Boolean,default: true},initialIndex: { // 指定轮播图初始显示的第几张幻灯片,默认显示第 1 张type: Number,default: 0},indicatorsInside: { // 控制指示器轮播区域内部/外部显示,true为在外部显示,false为在内部显示default: false},showNavButtons: {  // 控制左右按钮显示,这里默认隐藏type: Boolean,default: false}
});const currentIndex = ref(props.initialIndex);
const viewport = ref(null);
let autoPlayTimer = null;// 拖拽相关状态
const isDragging = ref(false);
const startPos = ref(0);
const currentTranslate = ref(0);
const prevTranslate = ref(0);
const animationId = ref(null);
const dragDistance = ref(0);// 计算当前显示的item
const currentItem = computed(() => {return props.items[currentIndex.value] || {};
});// 图片宽度配置
const slideConfig = {fullWidth: 680,visiblePart: 320,gap: 20
};// 计算轨道偏移量
const trackStyle = computed(() => {if (isDragging.value) {return {transform: `translateX(${currentTranslate.value}px)`,transition: 'none'};}const offset = currentIndex.value * -(slideConfig.fullWidth + slideConfig.gap);return {transform: `translateX(${offset}px)`,transition: 'transform 0.5s ease'};
});// 开始拖拽
const startDrag = (e) => {stopAutoPlay();isDragging.value = true;startPos.value = getPositionX(e);prevTranslate.value = currentIndex.value * -(slideConfig.fullWidth + slideConfig.gap);currentTranslate.value = prevTranslate.value;dragDistance.value = 0;cancelAnimationFrame(animationId.value);
};// 处理拖拽
const handleDrag = (e) => {if (!isDragging.value) return;const currentPosition = getPositionX(e);const diff = currentPosition - startPos.value;currentTranslate.value = prevTranslate.value + diff;dragDistance.value = Math.abs(diff);
};// 结束拖拽
const endDrag = () => {if (!isDragging.value) return;const movedBy = currentTranslate.value - prevTranslate.value;// 如果拖动距离超过100px,则切换幻灯片if (movedBy < -100 && currentIndex.value < props.items.length - 1) {currentIndex.value += 1;} else if (movedBy > 100 && currentIndex.value > 0) {currentIndex.value -= 1;}isDragging.value = false;resetAutoPlay();
};// 获取当前位置
const getPositionX = (e) => {return e.type.includes('mouse') ? e.pageX : e.touches[0].clientX;
};// 处理幻灯片点击
const handleSlideClick = (index) => {// 如果拖动距离大于10px,则不触发点击事件if (dragDistance.value > 10) return;goToDetail(props.items[index].id);
};// 切换上一张
const prevSlide = () => {currentIndex.value = (currentIndex.value - 1 + props.items.length) % props.items.length;resetAutoPlay();
};// 切换下一张
const nextSlide = () => {currentIndex.value = (currentIndex.value + 1) % props.items.length;resetAutoPlay();
};// 跳转到指定图片
const goToSlide = (index) => {currentIndex.value = index;resetAutoPlay();
};// 自动播放控制
const startAutoPlay = () => {if (!props.autoPlay) return;stopAutoPlay();autoPlayTimer = setInterval(() => {nextSlide();}, props.interval);
};const stopAutoPlay = () => {if (autoPlayTimer) {clearInterval(autoPlayTimer);autoPlayTimer = null;}
};const resetAutoPlay = () => {if (props.autoPlay) {stopAutoPlay();startAutoPlay();}
};// 监听autoPlay变化
watch(() => props.autoPlay, (newVal) => {if (newVal) {startAutoPlay();} else {stopAutoPlay();}
});// 监听initialIndex变化
watch(() => props.initialIndex, (newVal) => {if (newVal >= 0 && newVal < props.items.length) {currentIndex.value = newVal;}
});const goToDetail = (id) => {navigateTo({ path: `/case/${id}.html` });
};onMounted(() => {startAutoPlay();
});onBeforeUnmount(() => {stopAutoPlay();cancelAnimationFrame(animationId.value);
});
</script><style scoped>
.carousel-container {position: relative;width: 100%;max-width: 1280px;margin: 0 auto;height: 400px;user-select: none;
}.carousel-viewport {position: relative;width: 100%;height: 100%;overflow: hidden;cursor: grab;
}.carousel-viewport:active {cursor: grabbing;
}.carousel-track {display: flex;height: 100%;padding: 0 calc(50% - 340px);will-change: transform;
}.slide {flex: 0 0 680px;height: 100%;margin-right: 20px;position: relative;cursor: pointer;touch-action: pan-y;
}.slide img {width: 100%;height: 100%;object-fit: cover;border-radius: 10px;pointer-events: none;
}.slide-title {position: absolute;bottom: 0;right: 0;background: rgba(0, 0, 0, 0.5);color: white;text-align: center;padding: 8px 17px;border-radius: 10px 0px 10px 0px;font-size: 14px;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;transition: opacity 0.3s ease;
}/* 指示点样式 - 默认在外部 */
.indicators {position: absolute;bottom: 20px;left: 0;right: 0;display: flex;justify-content: center;gap: 10px;z-index: 20;
}/* 指示点在内部的样式 */
.indicators.inside {bottom: -30px;
}.indicators span {width: 10px;height: 10px;border-radius: 50%;background-color: #E0E0E0;cursor: pointer;transition: all 0.3s ease;
}.indicators span.active {background-color: #0A53B2;transform: scale(1.2);
}/* 标题和摘要样式 */
.carousel-caption {margin-top: 70px;text-align: center;padding: 0 20px;text-align: center;
}.carousel-title {font-size: 26px;font-weight: bold;margin-bottom: 16px;color: #333;
}.carousel-summary {font-size: 16px;color: #808080;line-height: 1.5;
}/* 导航按钮样式 */
.nav-button {position: absolute;top: 50%;transform: translateY(-50%);background: rgba(0, 0, 0, 0.5);color: white;border: none;width: 40px;height: 40px;border-radius: 50%;font-size: 20px;cursor: pointer;z-index: 20;display: flex;align-items: center;justify-content: center;
}.nav-button:hover {background: rgba(0, 0, 0, 0.8);
}.prev {left: 20px;
}.next {right: 20px;
}/* 响应式调整 */
@media (max-width: 768px) {.nav-button {width: 30px;height: 30px;font-size: 16px;}.prev {left: 10px;}.next {right: 10px;}
}
</style>

父组件使用:

<Carousel :items="list" :interval="3000" :autoPlay="true" :initialIndex="1" :indicatorsInside="true"/>

list 模拟数据可以用这个: 

const list = ref([{"id": 303,"categoryTag": "政府办公","title": "用智能化解决方案,助力政府完成办公基础设备搭建,系统管理全面升级","cover": "http://szdxyp.com/images/c02f612c-dd69-47ee-aafd-86aaa73df208.png","summary": "用智能化解决方案,简介xxxxxxxxxxxxxxxxxxxx",},{"id": 304,"categoryTag": "金融风控","title": "财富基石:金融数据与资产积累","cover": "http://szdxyp.com/images/1d128ffa-f4f0-485e-878c-86a708769a19.png","summary": "用智能化金融方案,简介xxxxxxxxxxxxxxxxxxxx硬币象征财富,图表代表金融数据,整体传达了金融数据在财富积累中的关键作用。",},{"id": 305,"categoryTag": "政府办公","title": "数字创想:代码世界的团队协作","cover": "http://szdxyp.com/images/080f8bdc-9133-4aaa-a34a-d9b965c23c24.png","summary": "用智能化金融方案,简介xxxxxxxxxxxxxxxxxxxx突出了编程协作在构建数字未来中的基础性作用,展示了团队合作的重要性。",},{"id": 306,"categoryTag": "智慧教育","title": "《协同共生:城市脉动与绿色能源的双向赋能》","cover": "http://szdxyp.com/images/3d670ed1-f68b-48d7-8bb6-d59d7d477846.png","summary": "展现出城市化进程与清洁能源发展的共生关系。左侧图片聚焦现代化城市的楼群林立与繁华交通,象征经济与技术的高度聚合;右侧呈现风力发电装置与太阳能板的能量转换场景,凸显对可再生能源的实践追求。两者结合,揭示了在全球化与生态危机并存的当下,城市与自然的平衡共生成为可持续发展的核心命题",},{"id": 307,"categoryTag": "金融风控","title": "清洁能源:生态可持续的技术突围","cover": "http://szdxyp.com/images/f4226060-347a-45d5-a379-3716189bc344.png","summary": "可再生能源实践:\n右侧风能、太阳能的规模化应用,体现了对化石能源的替代性突破,减少碳排放的同时,提高能源安全性与区域自主性。\n分布式能源趋势:\n结合城市楼宇光伏、社区微电网等场景,清洁能源可深度融入城市基础设施,形成“自给+共享”的能源网络。",}
])

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/87394.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/87394.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/87394.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

350+交付案例,高质量低成本构建智慧园区数字孪生交付新范式

在智慧园区建设领域&#xff0c;数字孪生技术正成为推动园区智能化转型的核心引擎。山东融谷信息凭借其全要素、全周期、全方位的数字孪生交付能力&#xff0c;已成功交付350余个项目&#xff0c;覆盖产业园区、智慧楼宇、智慧社区等多元场景&#xff0c;低成本高质量交付&…

OpenCV 图像像素类型转换与归一化

一、知识点 1、OpenCV支持多种数据类型&#xff0c;每种类型都对应着不同的取值范围。 (1)、CV_8U取值范围[0, 255]。 (2)、CV_16U取值范围[0, 65535]。 (3)、CV_32F取值范围[0, 1]。 2、OpenCV提供convertTo()函数来转换数据类型&#xff0c;提供normalize()函数来改…

机器学习算法_支持向量机

一、支持向量机 支持向量机只能做二分类任务 SVM全称支持向量机&#xff0c;即寻找到一个超平面使样本分成两类&#xff0c;且间隔最大 硬间隔&#xff1a;如果样本线性可分&#xff0c;在所有样本分类都正确的情况下&#xff0c;寻找最大间隔&#xff1b;如果出现异常值或样…

Linux : echo ~ tail 重定向符

&#x1f680; Linux 常用命令详解&#xff1a;echo、tail 与重定向符号全解析&#xff08;含通俗案例&#xff09; &#x1f4c5; 更新时间&#xff1a;2025年6月17日 &#x1f3f7;️ 标签&#xff1a;Linux基础 | Shell命令 | echo | tail | 输出重定向 | Linux入门 文章目录…

uniapp的更新流程【安卓、IOS、热更新】

UniApp应用更新方案 两种更新方式 APP全量升级&#xff1a;需要重新下载安装包热更新&#xff1a;通过下载wgt资源包实现&#xff0c;用户只需重启应用 Android更新实现 用户需要授权安装权限&#xff0c;流程为下载APK后自动弹出安装界面 var dtask plus.downloader.cre…

火山引擎解码生态型增长铁律

“技术流量与力量的崛起&#xff0c;本质上是一场生态规模的竞赛。每次浪潮的排头兵&#xff0c;都是指尖沾着代码的开发者——互联网时代的Linux社区让开源席卷全球&#xff0c;移动互联网的App Store催生百万开发者&#xff0c;而今天&#xff0c;大模型正在用API重构产业。”…

警惕GO的重复初始化

go的初始化方式有很多种&#xff0c;在某些情况下容易引起重复初始化导致错误。 事例如下&#xff1a; 当使用gorm连接数据库时定义了全局DB var DB *gorm.DB 但是在后面某个函数内部初始化时导致DB重新初始化变成了局部变量&#xff0c;导致原来的全局变量DB还是nil func I…

python校园服务交流系统

目录 技术栈介绍具体实现截图系统设计研究方法&#xff1a;设计步骤设计流程核心代码部分展示研究方法详细视频演示试验方案论文大纲源码获取/详细视频演示 技术栈介绍 Django-SpringBoot-php-Node.js-flask 本课题的研究方法和研究步骤基本合理&#xff0c;难度适中&#xf…

AlexNet:图像分类领域的里程碑网络及其创新剖析

文章目录 前言AlexNet一、网络的背景二、网络结构三、网络的创新3.1 首次使用GPU训练网络3.2 使用Relu激活函数3.2.1 sigmoid激活函数和tanh激活函数3.2.1.1 sigmoid激活函数3.2.1.2 tanh激活函数 3.3 Relu激活函数3.4 使用LRN局部响应归一化(已弃用)3.4.1 LRN的定义与起源3.4.…

iOS性能调优实践:结合KeyMob等多个工具提升应用稳定性与流畅度

在iOS应用开发中&#xff0c;性能问题往往难以通过单一工具轻松解决。尤其是当App面临用户反馈的流畅度差、卡顿严重、内存泄漏等问题时&#xff0c;开发者需要依靠多种工具的组合&#xff0c;才能有效地排查和优化性能瓶颈。 在我们最近的一个项目中&#xff0c;开发团队在处…

球形波方程的推导与解法

题目 问题 6. 一个球形波是三维波动方程的解,形式为 u ( r , t ) u(r,t) u(r,t),其中 r r r 是到原点的距离(球坐标)。波动方程的形式为: u t t = c 2 ( u r r + 2 r u r ) (球形波方程) . u_{tt} = c^{2} \left( u_{rr} + \frac{2}{r} u_{r} \right) \quad \text{(球形…

自动打电话软件设计与实现

文章目录 方案概述实现代码1. 安装必要的库2. 主程序代码3. HTML模板 (templates/index.html) 功能说明部署说明扩展功能建议注意事项 方案概述 使用Twilio的API进行电话呼叫实现基本的呼叫逻辑添加简单的用户界面 实现代码 1. 安装必要的库 pip install twilio flask2. 主…

RedissonLock源代码分析与锁应用

文章目录 前言一、RedissonLock源代码分析1.1 尝试加锁2.2 解锁 二、锁业务应用1.服务层方法注解方式 注入锁1.1 定义DistributedLock 注解类1.2 定义DistributedLockAspect 切片类1.3 尝试获取锁代码片断1.4 释放锁代码片断1.5 服务层注入锁注解 2.代码行加锁2.1 pom.xml文件引…

深入理解mysql索引

一、什么是索引&#xff1f; 索引&#xff08;Index&#xff09; 是数据库管理系统中一种特殊的数据结构&#xff0c;存储在磁盘上。它包含对数据表中一列或多列的值进行排序&#xff0c;并存储了指向表中实际数据行物理位置或主键值的引用指针。可以把它类比为书籍的目录&…

VMware vSphere Foundation 9.0 技术手册 —— Ⅰ 安装 ESXi 9.0 (虚拟机)

目录 1. 安装 ESXi 9.0 (虚拟机)&#xff08;1&#xff09;ESXi Standard Boot Menu&#xff08;2&#xff09;ESXi 安装导向&#xff08;3&#xff09;最终用户许可协议&#xff08;4&#xff09;选择系统盘&#xff08;5&#xff09;选择键盘类型&#xff08;6&#xff09;设…

UE5 游戏模板 —— TopDownGame 俯视角游戏

UE5 游戏模板 —— TopDownGame 俯视角游戏 前言一、模块导入二、TopDownGameMode三、TopDownPlayerController1、构造函数2、SetupInputComponent初始化新输入系统处理输入逻辑 四、TopDownCharacter五、射线检测总结 前言 上一篇文章介绍了一下PuzzleGame模板的流程&#xf…

基于深度学习的智能图像分割系统:技术与实践

前言 图像分割是计算机视觉领域中的一个核心任务&#xff0c;其目标是将图像划分为多个有意义的区域或对象。图像分割在医学影像分析、自动驾驶、安防监控等多个领域有着广泛的应用。近年来&#xff0c;深度学习技术&#xff0c;尤其是卷积神经网络&#xff08;CNN&#xff09;…

【学习笔记】2.2 Encoder-Decoder

参考资料&#xff1a;https://github.com/datawhalechina/happy-llm 在 Transformer 中&#xff0c;使用注意力机制的是其两个核心组件——Encoder&#xff08;编码器&#xff09;和 Decoder&#xff08;解码器&#xff09;。 2.2.1 Seq2Seq 模型 Seq2Seq&#xff08;序列到…

# 材料力学押题

材料力学押题 文章目录 材料力学押题第一题第二题组合变形弯曲变形 第一题 Q 求力作用的销钉位置的竖直偏移距离。 S 方法一:能量方法 材料应变能计算为: U ∫ 内力 2 2 刚度 d A U\int \frac{\text{内力}^2}{2\times 刚度}\text{d}A U∫2刚度内力2​dA 克拉珀龙原理&…

uniapp项目之小兔鲜儿小程序商城(一) 项目介绍,技术栈,小程序的基础架构,封装拦截器和请求函数

文章目录 一.项目介绍和前置内容1.重要链接2.技术栈 二.创建uniapp项目1.使用HBuilderX创建2.使用命令行创建3.如何使用vscode开发uniapp项目?step1:把项目拉入vscode,开始下相关插件step2:ts类型校验step3:设置json文件可以允许注释 4.pages.json文件的作用是什么?5.示例:在…