当前位置: 首页 > news >正文

vue3自定义无缝轮播组件

1.组件定义

<template><div:class="['carousel-container', isPaused ? 'show-arrows' : '']"@mouseenter="isPaused = true"@mouseleave="isPaused = false"><divclass="carousel-list":style="{transform: `translateX(-${currentIndex * 100}%)`,transition: isTransitioning ? 'transform 0.5s ease' : 'none',}"><divv-for="(image, index) in extendedImages":key="index"class="carousel-item":style="{ backgroundImage: `url(${image})` }"></div></div><div class="carousel-arrow carousel-arrow-left" @click="prevSlide"><span className="arrow-left"></span></div><div class="carousel-arrow carousel-arrow-right" @click="nextSlide"><span className="arrow-right"></span></div><div class="circles-container"><spanv-for="(_, index) in props.imageList":key="index":class="['circle', index === currentIndex - 1 ? 'active' : '']"@click="currentIndex = index + 1"></span></div><div class="autoplay-control"><button @click="isPaused == !isAutoPlaying">{{ isAutoPlaying ? "暂停" : "播放" }}</button></div></div>
</template>
<script lang="ts" setup>
const props = defineProps({imageList: {type: Array as PropType<string[]>,required: true,},interval: {type: Number,default: () => 2000,},autoPlay: {type: Boolean,default: () => false,},
});const currentIndex = ref<number>(1);
const isTransitioning = ref<boolean>(true);
const isAutoPlaying = ref<boolean>(props.autoPlay);
const isPaused = ref<boolean>(false);const extendedImages = [props.imageList[props.imageList.length - 1],...props.imageList,props.imageList[0],
];const nextSlide = () => {currentIndex.value += 1;isTransitioning.value = true;
};const prevSlide = () => {currentIndex.value -= 1;isTransitioning.value = true;
};watchEffect(onCleanup => {if (isAutoPlaying.value && !isPaused.value) {const timer = setInterval(nextSlide, props.interval);onCleanup(() => clearInterval(timer));}
});watch(currentIndex, newIndex => {if (newIndex === extendedImages.length - 1) {setTimeout(() => {isTransitioning.value = false;currentIndex.value = 1;}, 500);}if (newIndex === 0) {setTimeout(() => {isTransitioning.value = false;currentIndex.value = props.imageList.length;}, 500);}
});
</script>
<style scoped>
.carousel-container {display: flex;position: relative;align-items: center;justify-content: center;scroll-behavior: smooth;outline: 1px solid #dddedc;border-radius: 10px;width: 900px;height: 600px;margin: 30px auto;overflow: hidden;
}.carousel-list {display: flex;position: relative;height: 100%;width: 100%;scroll-snap-align: start;aspect-ratio: 5 / 3;
}.carousel-item {flex: 0 0 100%;height: 100%;background-size: cover;background-repeat: no-repeat;background-position: center;
}.carousel-arrow {position: absolute;width: 40px;height: 40px;border-radius: 50%;background: rgba(255, 255, 255, 0.7);display: flex;align-items: center;justify-content: center;cursor: pointer;z-index: 10;transition:opacity 0.3s ease,background 0.3s ease;opacity: 0;
}.carousel-container.show-arrows .carousel-arrow {opacity: 1;
}.carousel-arrow:hover {background: rgba(255, 255, 255, 0.9);
}.carousel-arrow-left {left: 10px;
}.carousel-arrow-right {right: 10px;
}.arrow-left,
.arrow-right {width: 12px;height: 12px;border-top: 2px solid #333;border-right: 2px solid #333;
}.arrow-left {transform: rotate(-135deg);margin-left: 4px;
}.arrow-right {transform: rotate(45deg);margin-right: 4px;
}.circles-container {display: flex;position: absolute;bottom: 20px;left: 50%;transform: translateX(-50%);gap: 20px;
}.circle {display: block;width: 24px;height: 24px;border-radius: 50%;background: transparent;border: 1px solid rgba(255, 255, 255, 0.7);cursor: pointer;transition: all 0.3s ease;
}.circle.active {background-color: rgb(249, 246, 246);border-color: white;
}.circle:hover {background-color: rgba(255, 255, 255, 0.5);
}.autoplay-control {position: absolute;top: 15px;right: 15px;
}.autoplay-control button {background: rgba(0, 0, 0, 0.2);color: white;border: none;padding: 5px 10px;border-radius: 4px;cursor: pointer;
}.autoplay-control button:hover {background: rgba(0, 0, 0, 0.7);
}
</style>

2.组件注册

在当前组件同目录创建index.ts,内容如下

import type { App } from "vue";
import SeamlessCarousel from "./index.vue";export default {install(app: App) {app.component("SeamlessCarousel", SeamlessCarousel);},
};

3.组件引入

在src的components目录下的index.ts中添加

import type { App } from "vue";
import SeamlessCarousel from "./SeamlessCarousel"const components = [SeamlessCarousel,
];export default {install(app: App) {components.map(item => {app.use(item);});},
};

4.组件使用

<template><div class="flex w-full mt-6"><SeamlessCarousel :imageList="sampleImages" :interval="5000" :autoPlay="true"/></div>
</template><script lang="ts" setup>import one from "@/views/seamlessCarousel/img/abstract-2512412.jpg";
import two from "@/views/seamlessCarousel/img/ai-generated-8061340.jpg";
import three from "@/views/seamlessCarousel/img/asian-422700.jpg";
import four from "@/views/seamlessCarousel/img/binary-978942.jpg";
import five from "@/views/seamlessCarousel/img/code-113611.jpg";
import six from "@/views/seamlessCarousel/img/fruit-7048114.jpg";
import seven from "@/views/seamlessCarousel/img/moss-4930309.jpg";
import eight from "@/views/seamlessCarousel/img/wood-591631.jpg";const sampleImages = [one, two, three, four, five, six, seven, eight];
</script>

这里使用的图片请自行。我这里使用了自动引入组件,所以不需要额外指定组件。

5.组件测试


文章转载自:

http://Mg86HcjX.pzdxg.cn
http://BA94bEuW.pzdxg.cn
http://dVkxyZ36.pzdxg.cn
http://OrKyZqkI.pzdxg.cn
http://692OiHBl.pzdxg.cn
http://6vhf9cvw.pzdxg.cn
http://wWf3YA7H.pzdxg.cn
http://I9AZQp3d.pzdxg.cn
http://QAscxkb5.pzdxg.cn
http://JjDj7WwH.pzdxg.cn
http://giGmY0oi.pzdxg.cn
http://506gvcL4.pzdxg.cn
http://Y64LRhPS.pzdxg.cn
http://RxWo5eGE.pzdxg.cn
http://nob4iiiY.pzdxg.cn
http://U9eHvvA4.pzdxg.cn
http://2mPGfVbt.pzdxg.cn
http://CHc1Yfn1.pzdxg.cn
http://LjYyCBv9.pzdxg.cn
http://KtDA9knW.pzdxg.cn
http://s4GSczCB.pzdxg.cn
http://fGiAZOJk.pzdxg.cn
http://uFFxlsgV.pzdxg.cn
http://OgdKJ9Xd.pzdxg.cn
http://ud2huVUw.pzdxg.cn
http://RraCSjqv.pzdxg.cn
http://jDwyHMX2.pzdxg.cn
http://NaIS7ZRL.pzdxg.cn
http://1Axg0dyF.pzdxg.cn
http://s5157DWJ.pzdxg.cn
http://www.dtcms.com/a/378309.html

相关文章:

  • 【每日算法】合并两个有序链表 LeetCode
  • 瑞萨RA家族新成员RA4C1,符合DLMS SUITE2表计安全规范、超低功耗、支持段码显示,专为智能表计应用开发
  • 【maxscript】矩阵对齐-武器残影
  • Java 黑马程序员学习笔记(进阶篇4)
  • XR 和 AI 在 Siggraph 2025 上主导图形的未来,获取gltf/glb格式
  • TikTok矩阵有哪些运营支撑方案?
  • 《基于深度学习的近红外条纹投影三维测量》-论文总结
  • 优选算法 100 题 —— 2 滑动窗口
  • MongoDB 在线安装-一键安装脚本(CentOS 7.9)
  • DeepSeek辅助编写的利用quick_xml把xml转为csv的rust程序
  • Rider中的Run/Debug配置对应的本地文件
  • 综合项目实践:基于基础语法核心的Python项目
  • 开始 ComfyUI 的 AI 绘图之旅-Flux.1图生图(八)
  • 供应商管理系统包含哪些模块?
  • MongoDB Atlas 云数据库实战:从零搭建全球多节点集群
  • Apache服务——搭建实验
  • “一半是火焰,一半是海水”,金融大模型的爆发与困局
  • 开源 C++ QT Widget 开发(十六)程序发布
  • MPC控制器C语言实现:基于一阶RL系统
  • C++版单例模式-现代化简洁写法
  • 强大的开源文档问答工具-Kotaemon
  • 音视频学习(六十三):AVCC和HVCC
  • 深度解析强化学习(RL):原理、算法与金融应用
  • 独立显卡和集成显卡切换电脑卡住了怎么办?
  • 加固笔记本是什么意思?加固笔记本图片
  • 光子精密3D线激光轮廓测量仪:赋能手机生产全流程质量与效率升级
  • springboot excel 表格入门与实战
  • react实现无缝轮播组件
  • DbGate数据库管理新方案:cpolar打造跨平台远程访问通道
  • Spark+Hive中间件