可自定义设置以下属性:
-
走马灯图片数组(images),类型:Array<{title: string, src: string , link?: string}>,必传,默认 []
-
走马灯宽度(width),类型:number | string,单位 px,默认 '100%'
-
走马灯高度(height),类型:number | string,单位 px,默认 '100vh'
-
是否自动切换(autoplay),类型:boolean,默认 false
-
当鼠标移入走马灯时,是否暂停自动轮播(pauseOnMouseEnter),类型:boolean,默认 false
-
轮播图切换时的过渡效果(effect),类型:'slide' | 'fade',默认 'slide'
-
自动轮播间隔(interval),类型:number,单位ms,默认 3000ms
-
是否显示箭头(showArrow),类型:boolean,默认 true
-
箭头颜色(arrowColor),类型:string,默认 '#FFF'
-
箭头大小(arrowSize),类型:number,单位px,默认 36
-
是否显示指示点(dots),类型:boolean,默认 true
-
指示点大小(dotSize),类型:number,单位px,默认 10
-
指示点颜色(dotColor),类型:string,默认 'rgba(255, 255, 255, 0.3)'
-
指示点选中颜色(dotActiveColor),类型:string,默认 '#1677FF'
-
指示点样式(dotStyle),优先级高于 dotSize、dotColor,类型:CSSProperties,默认 {}
-
指示点位置(dotPosition),位置为 'left' | 'right' 时,effect: 'slide' 轮播自动变为垂直轮播,类型:'bottom'|'top'|'left'|'right',默认 'bottom'
-
指示点触发切换的方式(dotsTrigger),类型:'click' | 'hover',默认 'click'
-
图片加载中样式,Spin 组件属性配置(spinProps),参考 Spin Props,类型:object,默认 {}
-
渐变动画持续时长(fadeDuration),类型:number,单位 ms,仅当 effect 为 'fade' 时生效,默认 500
-
渐变动画函数(fadeFunction),类型:string,仅当 effect 为 'fade' 时生效,默认 'cubic-bezier(0.4, 0, 0.2, 1)',可参考 transition-timing-function
-
滑动动画持续时长(slideDuration),类型:number,单位 ms,仅当 effect 为 'slide' 时生效,默认 1000
-
滑动动画函数(slideFunction),类型:number[],仅当 effect 为 'slide' 时生效,默认 [0.65, 0, 0.35, 1],可参考 useTransition
效果如下图:
在线预览
安装 @vueuse/core:
pnpm add @vueuse/core
①创建走马灯组件Carousel.vue:
其中引入使用了以下工具函数与组件:
- Vue3加载(Spin)
- 使用requestAnimationFrame模拟实现setTimeout和setInterval
- 事件监听 useEventListener
- 监听DOM尺寸 useResizeObserver
<script setup lang="ts">
import { ref, computed, watch } from 'vue'
import type { CSSProperties } from 'vue'
import { rafTimeout, cancelRaf, useEventListener, useResizeObserver } from '../utils'
import { useTransition } from '@vueuse/core'
import Spin from '../spin'
interface Image {
title?: string // 图片名称
src: string // 图片地址
link?: string // 图片跳转链接
}
interface Props {
images?: Image[] // 走马灯图片数组
width?: number | string // 走马灯宽度,单位 px
height?: number | string // 走马灯高度,单位 px
autoplay?: boolean // 是否自动轮播
pauseOnMouseEnter?: boolean // 当鼠标移入走马灯时,是否暂停自动轮播
effect?: 'slide' | 'fade' // 轮播图切换时的过渡效果
interval?: number // 自动轮播间隔,单位 ms
showArrow?: boolean // 是否显示箭头
arrowColor?: string // 箭头颜色
arrowSize?: number // 箭头大小,单位 px
dots?: boolean // 是否显示指示点
dotSize?: number // 指示点大小,单位 px
dotColor?: string // 指示点颜色
dotActiveColor?: string // 指示点选中颜色
dotStyle?: CSSProperties // 指示点样式,优先级高于 dotSize、dotColor
dotActiveStyle?: CSSProperties // 指示点选中样式,优先级高于 dotActiveColor
dotPosition?: 'bottom' | 'top' | 'left' | 'right' // 指示点位置,位置为 'left' | 'right' 时,effect: 'slide' 轮播自动变为垂直轮播
dotsTrigger?: 'click' | 'hover' // 指示点触发切换的方式
spinProps?: object // 图片加载中样式,Spin 组件属性配置,参考 Spin Props
fadeDuration?: number // 渐变动画持续时长,单位 ms,仅当 effect 为 'fade' 时生效
fadeFunction?: string // 渐变动画函数,仅当 effect 为 'fade' 时生效,可参考 transition-timing-function 写法:https://developer.mozilla.org/zh-CN/docs/Web/CSS/transition-timing-function
slideDuration?: number // 滑动动画持续时长,单位 ms,仅当 effect 为 'slide' 时生效
slideFunction?: string | number[] // 滑动动画函数,仅当 effect 为 'slide' 时生效,可参考 useTransition 写法:https://vueuse.org/core/useTransition/#usage
}
const props = withDefaults(defineProps<Props>(), {
images: () => [],
width: '100%',
height: '100vh',
autoplay: false,
pauseOnMouseEnter: false,
effect: 'slide',
interval: 3000,
showArrow: true,
arrowColor: '#FFF',
arrowSize: 36,
dots: true,
dotSize: 10,
dotColor: 'rgba(255, 255, 255, 0.3)',
dotActiveColor: '#1677FF',
dotStyle: () => ({}),
dotActiveStyle: () => ({}),
dotPosition: 'bottom',
dotsTrigger: 'click',
spinProps: () => ({}),
fadeDuration: 500,
fadeFunction: 'cubic-bezier(0.4, 0, 0.2, 1)',
slideDuration: 800,
slideFunction: () => [0.65, 0, 0.35, 1]
})
const offset = ref(0) // 滑动偏移值
const slideTimer = ref() // 轮播切换定时器
const stopCarousel = ref(false) // 鼠标悬浮时,停止切换标志
const switchPrevent = ref(false) // 在滑动切换过程中,禁用其他所有切换操作
const moveEffectRaf = ref() // 移动过程 requestAnimationFrame 的返回值,一个 long 整数,请求 ID,是回调列表中唯一的标识
const targetPosition = ref() // 目标移动位置
const carouselRef = ref() // carousel DOM 引用
const activeSwitcher = ref(1) // 当前展示图片标识
const imageWidth = ref() // 图片宽度
const imageHeight = ref() // 图片高度
const complete = ref(Array(props.images.length).fill(false)) // 图片是否加载完成
const emits = defineEmits(['change', 'click'])
const carouselWidth = computed(() => {
// 走马灯区域宽度
if (typeof props.width === 'number') {
return `${props.width}px`
} else {
return props.width
}
})
const carouselHeight = computed(() => {
// 走马灯区域高度
if (typeof props.height === 'number') {
return `${props.height}px`
} else {
return props.height
}
})
const imageAmount = computed(() => {
// 轮播图片数量
return props.images.length
})
const verticalSlide = computed(() => {
// 是否垂直轮播
return ['left', 'right'].includes(props.dotPosition)
})
const moveUnitDistance = computed(() => {
// 每次移动的单位距离
if (verticalSlide.value) {
return imageHeight.value
} else {
return imageWidth.value
}
})
const carouselStyle = computed(() => {
if (props.effect === 'slide') {
return {
transform: (verticalSlide.value ? 'translateY' : 'translateX') + `(${-offset.value}px)`
}
} else {
return {}
}
})
watch(
() => [
verticalSlide.value,
props.effect,
props.images,
props.autoplay,
props.interval,
props.fadeDuration,
props.fadeFunction,
complete.value[0]
],
() => {
initCarousel()
},
{
deep: true,
flush: 'post'
}
)
watch(activeSwitcher, (to) => {
emits('change', to)
})
useEventListener(document, 'visibilitychange', visibilityChange)
useResizeObserver(carouselRef, () => {
getImageSize()
initCarousel()
})
function initCarousel() {
slideTimer.value && cancelRaf(slideTimer.value)
moveEffectRaf.value && cancelAnimationFrame(moveEffectRaf.value)
switchPrevent.value = false
if (props.effect === 'slide') {
offset.value = (activeSwitcher.value - 1) * moveUnitDistance.value
}
onStart()
}
function onComplete(index: number) {
// 图片加载完成
complete.value[index] = true
}
function getImageSize() {
// 获取每张图片大小
imageWidth.value = carouselRef.value.offsetWidth
imageHeight.value = carouselRef.value.offsetHeight
}
function onKeyboard(e: KeyboardEvent) {
if (imageAmount.value > 1) {
if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') {
onLeftArrow()
}
if (e.key === 'ArrowRight' || e.key === 'ArrowDown') {
onRightArrow()
}
}
}
// 当用户导航到新页面、切换标签页、关闭标签页、最小化或关闭浏览器,或者在移动设备上从浏览器切换到不同的应用程序时,暂停切换
function visibilityChange() {
console.log('visibilityState', document.visibilityState)
const visibility = document.visibilityState
if (visibility === 'hidden') {
// hidden
slideTimer.value && cancelRaf(slideTimer.value)
offset.value = originNumber.value + distance.value
switchPrevent.value = false
} else {
// visible
onStart()
}
}
function onStart() {
if (props.autoplay && imageAmount.value > 1 && complete.value[0]) {
// 超过一条时滑动
stopCarousel.value = false
autoSlide() // 自动滑动轮播
console.log('Carousel Start')
}
}
function onStop() {
slideTimer.value && cancelRaf(slideTimer.value)
stopCarousel.value = true
console.log('Carousel Stop')
}
function autoSlide() {
if (!stopCarousel.value) {
slideTimer.value && cancelRaf(slideTimer.value)
slideTimer.value = rafTimeout(() => {
switchPrevent.value = true // 禁用导航切换
if (props.effect === 'slide') {
const target = (offset.value % (imageAmount.value * moveUnitDistance.value)) + moveUnitDistance.value
moveLeft(target)
activeSwitcher.value = (activeSwitcher.value % imageAmount.value) + 1
} else {
// fade
moveFade('left')
}
}, props.interval)
}
}
function onLeftArrow() {
if (!switchPrevent.value) {
switchPrevent.value = true
slideTimer.value && cancelRaf(slideTimer.value)
if (props.effect === 'slide') {
const target = ((activeSwitcher.value + imageAmount.value - 2) % imageAmount.value) * moveUnitDistance.value
moveRight(target)
activeSwitcher.value = activeSwitcher.value - 1 > 0 ? activeSwitcher.value - 1 : imageAmount.value
} else {
// fade
moveFade('right')
}
}
}
function onRightArrow() {
if (!switchPrevent.value) {
switchPrevent.value = true
slideTimer.value && cancelRaf(slideTimer.value)
if (props.effect === 'slide') {
const target = activeSwitcher.value * moveUnitDistance.value
moveLeft(target)
activeSwitcher.value = (activeSwitcher.value % imageAmount.value) + 1
} else {
// fade
moveFade('left')
}
}
}
const baseNumber = ref(0)
const originNumber = ref(0) // 初始位置
const distance = ref(0) // 滑动距离
// @ts-ignore
const cubicBezierNumber = useTransition(baseNumber, {
duration: props.slideDuration, // 过渡动画时长
transition: props.slideFunction // 过渡动画函数
})
function moveFade(direction: 'left' | 'right' | 'switch', n?: number) {
if (direction === 'left') {
activeSwitcher.value = (activeSwitcher.value % imageAmount.value) + 1
} else if (direction === 'right') {
activeSwitcher.value = activeSwitcher.value - 1 > 0 ? activeSwitcher.value - 1 : imageAmount.value
} else {
activeSwitcher.value = n as number
}
rafTimeout(() => {
switchPrevent.value = false
if (props.autoplay) {
autoSlide()
}
}, props.fadeDuration)
}
function toggleNumber(target: number) {
targetPosition.value = target
baseNumber.value = baseNumber.value ? 0 : 1
originNumber.value = offset.value // 初始位置
distance.value = target - originNumber.value // 总距离
}
function moveEffect() {
// 滑动效果函数
if (baseNumber.value) {
offset.value = originNumber.value + distance.value * cubicBezierNumber.value
} else {
offset.value = originNumber.value + distance.value * (1 - cubicBezierNumber.value)
}
}
function moveLeftEffect() {
if (offset.value >= targetPosition.value) {
switchPrevent.value = false
if (props.autoplay) {
autoSlide() // 自动间隔切换下一张
}
} else {
moveEffect()
moveEffectRaf.value = requestAnimationFrame(moveLeftEffect)
}
}
function moveLeft(target: number) {
// 箭头切换或跳转切换,向左滑动效果
if (offset.value === imageAmount.value * moveUnitDistance.value) {
// 最后一张时,重置left
offset.value = 0
}
toggleNumber(target)
moveEffectRaf.value = requestAnimationFrame(moveLeftEffect)
}
function moveRightEffect() {
if (offset.value <= targetPosition.value) {
switchPrevent.value = false
if (props.autoplay) {
autoSlide()
}
} else {
moveEffect()
moveEffectRaf.value = requestAnimationFrame(moveRightEffect)
}
}
function moveRight(target: number) {
// 箭头切换或跳转切换,向右滑动效果
if (offset.value === 0) {
// 第一张时,重置left
offset.value = imageAmount.value * moveUnitDistance.value
}
toggleNumber(target)
moveEffectRaf.value = requestAnimationFrame(moveRightEffect)
}
function onSwitch(n: number) {
// 分页切换图片
if (!switchPrevent.value && activeSwitcher.value !== n) {
switchPrevent.value = true
slideTimer.value && cancelRaf(slideTimer.value)
if (n < activeSwitcher.value) {
// 往右滑动
if (props.effect === 'slide') {
const target = (n - 1) * moveUnitDistance.value
moveRight(target)
activeSwitcher.value = n
} else {
// fade
moveFade('switch', n)
}
}
if (n > activeSwitcher.value) {
// 往左滑动
if (props.effect === 'slide') {
const target = (n - 1) * moveUnitDistance.value
moveLeft(target)
activeSwitcher.value = n
} else {
// fade
moveFade('switch', n)
}
}
}
}
function onMouseEnter(n: number) {
onSwitch(n)
}
function clickImage(image: Image) {
emits('click', image)
}
function to(n: number): void {
if (n >= 1 && n <= imageAmount.value) {
onSwitch(n)
}
}
function prev(): void {
onLeftArrow()
}
function next(): void {
onRightArrow()
}
function getCurrentIndex(): number {
return activeSwitcher.value
}
defineExpose({
to,
prev,
next,
getCurrentIndex
})
</script>
<template>
<div
ref="carouselRef"
class="m-carousel"
:class="{ 'carousel-vertical': verticalSlide, 'carousel-fade': effect === 'fade' }"
:style="`--arrow-color: ${arrowColor}; --dot-size: ${dotSize}px; --dot-color: ${dotColor}; --fade-duration: ${props.fadeDuration}ms; --fade-function: ${props.fadeFunction}; width: ${carouselWidth}; height: ${carouselHeight};`"
@mouseenter="autoplay && pauseOnMouseEnter ? onStop() : () => false"
@mouseleave="autoplay && pauseOnMouseEnter ? onStart() : () => false"
>
<div class="m-carousel-flex" :style="carouselStyle">
<div
class="m-image"
:class="{ 'image-fade-active': effect === 'fade' && activeSwitcher === index + 1 }"
@click="clickImage(image)"
v-for="(image, index) in images"
:key="index"
>
<Spin :spinning="!complete[index]" indicator="dynamic-circle" v-bind="spinProps">
<img
@load="onComplete(index)"
:src="image.src"
:key="image.src"
:alt="image.title"
class="u-image"
:style="`width: ${imageWidth}px; height: ${imageHeight}px;`"
/>
</Spin>
</div>
<div class="m-image" @click="clickImage(images[0])" v-if="imageAmount && effect === 'slide'">
<Spin :spinning="!complete[0]" indicator="dynamic-circle" v-bind="spinProps">
<img
@load="onComplete(0)"
:src="images[0].src"
:key="images[0].src"
:alt="images[0].title"
class="u-image"
:style="`width: ${imageWidth}px; height: ${imageHeight}px;`"
/>
</Spin>
</div>
</div>
<template v-if="showArrow">
<svg
tabindex="0"
class="arrow-left"
:style="`width: ${arrowSize}px; height: ${arrowSize}px;`"
@click="onLeftArrow"
@keydown.prevent="onKeyboard"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
>
<path
d="M10.26 3.2a.75.75 0 0 1 .04 1.06L6.773 8l3.527 3.74a.75.75 0 1 1-1.1 1.02l-4-4.25a.75.75 0 0 1 0-1.02l4-4.25a.75.75 0 0 1 1.06-.04z"
></path>
</svg>
<svg
tabindex="0"
class="arrow-right"
:style="`width: ${arrowSize}px; height: ${arrowSize}px;`"
@click="onRightArrow"
@keydown.prevent="onKeyboard"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
>
<path
d="M5.74 3.2a.75.75 0 0 0-.04 1.06L9.227 8L5.7 11.74a.75.75 0 1 0 1.1 1.02l4-4.25a.75.75 0 0 0 0-1.02l-4-4.25a.75.75 0 0 0-1.06-.04z"
></path>
</svg>
</template>
<div class="m-switch" :class="`switch-${dotPosition}`" v-if="dots">
<div
tabindex="0"
class="u-dot"
:style="[dotStyle, activeSwitcher === n ? { backgroundColor: dotActiveColor, ...dotActiveStyle } : {}]"
v-for="n in imageAmount"
:key="n"
@click="dotsTrigger === 'click' ? onSwitch(n) : () => false"
@mouseenter="dotsTrigger === 'hover' ? onMouseEnter(n) : () => false"
@keydown.prevent="onKeyboard"
></div>
</div>
</div>
</template>
<style lang="less" scoped>
.m-carousel {
display: inline-block;
margin: 0 auto;
position: relative;
overflow: hidden;
.m-carousel-flex {
display: flex;
width: 100%;
height: 100%;
// will-change: transform;
.m-image {
// 指定了 flex 元素的收缩规则。flex 元素仅在默认宽度之和大于容器的时候才会发生收缩,其收缩的大小是依据 flex-shrink 的值
flex-shrink: 0; // 默认为 1,为 0 时不缩小
display: inline-block;
cursor: pointer;
.u-image {
display: inline-block;
object-fit: cover;
vertical-align: bottom; // 消除img标签底部的5px
}
}
}
&:hover {
.arrow-left {
opacity: 0.7;
pointer-events: auto;
}
.arrow-right {
opacity: 0.7;
pointer-events: auto;
}
}
.arrow-left {
position: absolute;
left: 6px;
top: 50%;
transform: translateY(-50%);
color: var(--arrow-color);
fill: currentColor;
cursor: pointer;
opacity: 0;
pointer-events: none;
outline: none;
transition: opacity 0.3s;
&:hover {
opacity: 1;
}
}
.arrow-right {
position: absolute;
right: 6px;
top: 50%;
transform: translateY(-50%);
color: var(--arrow-color);
fill: currentColor;
cursor: pointer;
opacity: 0;
pointer-events: none;
outline: none;
transition: opacity 0.3s;
&:hover {
opacity: 1;
}
}
.m-switch {
display: flex;
justify-content: center;
gap: 8px;
position: absolute;
z-index: 9;
bottom: 12px;
left: 50%;
transform: translateX(-50%);
height: auto;
.u-dot {
// flex: 0 1 auto;
width: var(--dot-size);
height: var(--dot-size);
border-radius: var(--dot-size);
background-color: var(--dot-color);
cursor: pointer;
outline: none;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
}
.switch-top {
top: 12px;
bottom: auto;
}
.switch-left {
left: 12px;
right: auto;
top: 50%;
bottom: auto;
transform: translateY(-50%);
flex-direction: column;
}
.switch-right {
right: 12px;
left: auto;
top: 50%;
bottom: auto;
transform: translateY(-50%);
flex-direction: column;
}
}
.carousel-vertical {
.m-carousel-flex {
flex-direction: column;
}
.arrow-left {
top: 6px;
left: 50%;
transform: translateX(-50%) rotate(90deg);
}
.arrow-right {
top: auto;
bottom: 6px;
left: 50%;
transform: translateX(-50%) rotate(90deg);
}
}
.carousel-fade {
.m-image {
position: absolute;
opacity: 0;
pointer-events: none;
transition-property: opacity;
transition-duration: var(--fade-duration);
transition-timing-function: var(--fade-function);
}
.image-fade-active {
opacity: 1;
pointer-events: auto;
}
}
</style>
其中引入使用了以下组件:
- Vue3间距(Space)
- Vue3单选框(Radio)
- Vue3选择器(Select)
- Vue3数字输入框(InputNumber)
- Vue3按钮(Button)
- Vue3弹性布局(Flex)
- Vue3栅格(Grid)
- Vue3开关(Switch)
- Vue3滑动输入条(Slider)
- Vue3输入框(Input)
②在要使用的页面引入:
<script setup lang="ts">
import Carousel from './Carousel.vue'
import { ref, reactive } from 'vue'
const images = ref([
{
title: 'image-1',
src: 'https://cdn.jsdelivr.net/gh/themusecatcher/resources@0.0.5/1.jpg',
link: ''
},
{
title: 'image-2',
src: 'https://cdn.jsdelivr.net/gh/themusecatcher/resources@0.0.5/2.jpg',
link: ''
},
{
title: 'image-3',
src: 'https://cdn.jsdelivr.net/gh/themusecatcher/resources@0.0.5/3.jpg',
link: ''
},
{
title: 'image-4',
src: 'https://cdn.jsdelivr.net/gh/themusecatcher/resources@0.0.5/4.jpg',
link: ''
},
{
title: 'image-5',
src: 'https://cdn.jsdelivr.net/gh/themusecatcher/resources@0.0.5/5.jpg',
link: ''
},
{
title: 'image-6',
src: 'https://cdn.jsdelivr.net/gh/themusecatcher/resources@0.0.5/6.jpg',
link: ''
},
{
title: 'image-7',
src: 'https://cdn.jsdelivr.net/gh/themusecatcher/resources@0.0.5/7.jpg',
link: ''
},
{
title: 'image-8',
src: 'https://cdn.jsdelivr.net/gh/themusecatcher/resources@0.0.5/8.jpg',
link: ''
},
{
title: 'image-9',
src: 'https://cdn.jsdelivr.net/gh/themusecatcher/resources@0.0.5/9.jpg',
link: ''
}
])
const showArrow = ref(false)
const positionOptions = ref([
{
label: 'top',
value: 'top'
},
{
label: 'bottom',
value: 'bottom'
},
{
label: 'left',
value: 'left'
},
{
label: 'right',
value: 'right'
}
])
const dotPosition = ref('top')
const effectOptions = ref([
{
label: 'slide',
value: 'slide'
},
{
label: 'fade',
value: 'fade'
}
])
const effect = ref('fade')
const triggerOptions = ref([
{
label: 'click',
value: 'click'
},
{
label: 'hover',
value: 'hover'
}
])
const trigger = ref('hover')
function clickImage(image: object) {
console.log('image', image)
}
function onChange(index: number) {
console.log('change', index)
}
const carousel = ref()
const toIndex = ref(1)
const currentIndex = ref(1)
function getCurrentIndex() {
currentIndex.value = carousel.value.getCurrentIndex()
}
const carouselConfig = reactive({
autoplay: true,
pauseOnMouseEnter: false,
effect: 'slide',
interval: 3000,
showArrow: true,
arrowColor: '#FFF',
arrowSize: 36,
dots: true,
dotSize: 10,
dotColor: 'rgba(255, 255, 255, 0.3)',
dotActiveColor: '#1677FF',
dotPosition: 'bottom',
dotsTrigger: 'click',
fadeDuration: 500,
fadeFunction: 'cubic-bezier(0.4, 0, 0.2, 1)'
})
</script>
<template>
<div>
<h1>{{ $route.name }} {{ $route.meta.title }}</h1>
<h2 class="mt30 mb10">基本使用</h2>
<h3 class="mb10">当焦点在 Arrow 或 Dots 上时,可以通过键盘上、下、左、右按键切换</h3>
<Carousel :images="images" :width="800" :height="450" @click="clickImage" />
<h2 class="mt30 mb10">箭头</h2>
<Space align="center"> showArrow: <Switch v-model="showArrow" /> </Space>
<br />
<br />
<Carousel :images="images" :width="800" :height="450" :show-arrow="showArrow" @click="clickImage" />
<h2 class="mt30 mb10">自动轮播</h2>
<Carousel :images="images" :width="800" :height="450" autoplay @change="onChange" @click="clickImage" />
<h2 class="mt30 mb10">指示点位置</h2>
<Radio :options="positionOptions" v-model:value="dotPosition" button button-style="solid" />
<br />
<br />
<Carousel :images="images" :width="800" :height="450" autoplay :dotPosition="dotPosition" />
<h2 class="mt30 mb10">垂直</h2>
<Carousel :images="images" :width="800" :height="450" autoplay dotPosition="right" />
<h2 class="mt30 mb10">移入暂停</h2>
<Carousel :images="images" :width="800" :height="450" autoplay pause-on-mouse-enter dotPosition="right" />
<h2 class="mt30 mb10">过渡效果</h2>
<Radio :options="effectOptions" v-model:value="effect" button button-style="solid" />
<br />
<br />
<Carousel :images="images" :width="800" :height="450" :effect="effect" :fade-duration="1500" />
<h2 class="mt30 mb10">鼠标经过指示点切换轮播图</h2>
<Radio :options="triggerOptions" v-model:value="trigger" button button-style="solid" />
<br />
<br />
<Carousel :images="images" :width="800" :height="450" :dots-trigger="trigger" />
<h2 class="mt30 mb10">自定义滑动动画</h2>
<Carousel :images="images" :width="800" :height="450" :slide-duration="800" :slide-function="[0.45, 1, 0.55, 1]" />
<h2 class="mt30 mb10">自定义样式</h2>
<Carousel
:images="images"
:width="800"
:height="450"
arrow-color="#13C2C2"
:arrow-size="48"
dot-active-color="#13C2C2"
:dot-style="{ backgroundColor: '#FFF' }"
:dot-active-style="{ width: '25px', backgroundColor: 'gold' }"
:spin-style="{ indicator: 'dot', color: '#13C2C2' }"
/>
<h2 class="mt30 mb10">使用 Carousel Methods</h2>
<Space>
<InputNumber :min="1" :max="images.length" v-model:value="toIndex" />
<Button @click="carousel.to(toIndex)">跳转到</Button>
<Button @click="carousel.prev()">前一页</Button>
<Button @click="carousel.next()">后一页</Button>
<Button @click="getCurrentIndex">获取当前页:{{ currentIndex }}</Button>
</Space>
<br />
<br />
<Carousel ref="carousel" :images="images" :width="800" :height="450" />
<h2 class="mt30 mb10">走马灯配置器</h2>
<Flex gap="large" vertical>
<Row :gutter="[24, 12]">
<Col :span="6">
<Space gap="small" vertical> autoplay:<Switch v-model="carouselConfig.autoplay" /> </Space>
</Col>
<Col :span="6">
<Space gap="small" vertical>
pauseOnMouseEnter:<Switch v-model="carouselConfig.pauseOnMouseEnter" />
</Space>
</Col>
<Col :span="6">
<Space gap="small" vertical>
effect:<Radio :options="effectOptions" v-model:value="carouselConfig.effect" button button-style="solid" />
</Space>
</Col>
<Col :span="6">
<Flex gap="small" vertical>
interval:<Slider v-model:value="carouselConfig.interval" :min="100" :step="10" :max="10000" />
</Flex>
</Col>
<Col :span="6">
<Space gap="small" vertical> showArrow:<Switch v-model="carouselConfig.showArrow" /> </Space>
</Col>
<Col :span="6">
<Flex gap="small" vertical>
arrowColor:<Input v-model:value="carouselConfig.arrowColor" placeholder="arrowColor" />
</Flex>
</Col>
<Col :span="6">
<Flex gap="small" vertical> arrowSize:<Slider v-model:value="carouselConfig.arrowSize" :min="1" /> </Flex>
</Col>
<Col :span="6"></Col>
<Col :span="6">
<Space gap="small" vertical> dots:<Switch v-model="carouselConfig.dots" /> </Space>
</Col>
<Col :span="6">
<Flex gap="small" vertical> dotSize:<Slider v-model:value="carouselConfig.dotSize" :min="4" :max="64" /> </Flex>
</Col>
<Col :span="6">
<Flex gap="small" vertical> dotColor:<Input v-model:value="carouselConfig.dotColor" placeholder="dotColor" /> </Flex>
</Col>
<Col :span="6">
<Flex gap="small" vertical>
dotActiveColor:<Input v-model:value="carouselConfig.dotActiveColor" placeholder="dotActiveColor" />
</Flex>
</Col>
<Col :span="6">
<Flex gap="small" vertical>
dotPosition:
<Select :options="positionOptions" v-model="carouselConfig.dotPosition" />
</Flex>
</Col>
<Col :span="6">
<Space gap="small" vertical>
dotsTrigger:
<Radio :options="triggerOptions" v-model:value="carouselConfig.dotsTrigger" button button-style="solid" />
</Space>
</Col>
<Col :span="6">
<Flex gap="small" vertical>
fadeDuration:<Slider v-model:value="carouselConfig.fadeDuration" :min="100" :step="10" :max="10000" />
</Flex>
</Col>
<Col :span="6">
<Flex gap="small" vertical>
fadeFunction:<Input v-model:value="carouselConfig.fadeFunction" placeholder="fadeFunction" />
</Flex>
</Col>
</Row>
<Carousel
:images="images"
:height="450"
:autoplay="carouselConfig.autoplay"
:pause-on-mouse-enter="carouselConfig.pauseOnMouseEnter"
:effect="carouselConfig.effect"
:interval="carouselConfig.interval"
:show-arrow="carouselConfig.showArrow"
:arrow-color="carouselConfig.arrowColor"
:arrow-size="carouselConfig.arrowSize"
:dots="carouselConfig.dots"
:dot-size="carouselConfig.dotSize"
:dot-color="carouselConfig.dotColor"
:dot-active-color="carouselConfig.dotActiveColor"
:dot-position="carouselConfig.dotPosition"
:dots-trigger="carouselConfig.dotsTrigger"
:fade-duration="carouselConfig.fadeDuration"
:fade-function="carouselConfig.fadeFunction"
:spin-style="{ indicator: 'dot', color: '#13C2C2' }"
/>
</Flex>
</div>
</template>