diff --git a/components/carousel/arrow.tsx b/components/carousel/arrow.tsx index abd29300..51718307 100644 --- a/components/carousel/arrow.tsx +++ b/components/carousel/arrow.tsx @@ -1,15 +1,9 @@ -import { - defineComponent, - computed, - inject, - Fragment, - Transition, - type ComponentObjectPropsOptions, -} from 'vue'; +import { defineComponent, computed, inject, Fragment, Transition } from 'vue'; import { throttle } from 'lodash-es'; import { LeftOutlined, RightOutlined } from '../icon'; import { provideKey } from './const'; -import type { CarouselItemData } from './interface'; +import type { PropType, ComponentObjectPropsOptions } from 'vue'; +import type { CarouselItemData, ArrowType } from './interface'; export default defineComponent({ name: 'FCarouselArrow', @@ -22,32 +16,37 @@ export default defineComponent({ type: Boolean, required: true, }, + showArrow: { + type: String as PropType, + default: 'hover', + }, activeIndex: Number, } satisfies ComponentObjectPropsOptions, setup(props) { const { prefixCls, direction, + rootProps, slideChildren, - showArrow, - loop, setActiveItem, } = inject(provideKey); const arrowVisible = computed( - () => showArrow !== 'never' && direction.value === 'horizontal', + () => + props.showArrow !== 'never' && direction.value === 'horizontal', ); const arrowLeftShow = computed( () => - (showArrow === 'always' || props.hover) && - (loop || props.activeIndex > 0), + (props.showArrow === 'always' || props.hover) && + (rootProps.loop || props.activeIndex > 0), ); const arrowRightShow = computed( () => - (showArrow === 'always' || props.hover) && - (loop || props.activeIndex < slideChildren.value.length - 1), + (props.showArrow === 'always' || props.hover) && + (rootProps.loop || + props.activeIndex < slideChildren.value.length - 1), ); const slideItemInStage = ( diff --git a/components/carousel/carousel-item.tsx b/components/carousel/carousel-item.tsx index 89fa5453..3eda1ce5 100644 --- a/components/carousel/carousel-item.tsx +++ b/components/carousel/carousel-item.tsx @@ -59,8 +59,7 @@ export default defineComponent({ prefixCls, direction, wrapperRef, - type: parentType, - loop, + rootProps, slideChildren, setActiveItem, addItem, @@ -130,16 +129,15 @@ export default defineComponent({ oldIndex: number, ) => { const length = slideChildren.value.length; - // eslint-disable-next-line no-undefined - if (parentType !== 'card' && oldIndex !== undefined) { + if (rootProps.type !== 'card' && oldIndex !== undefined) { itemStatus.animating = index === activeIndex || index === oldIndex; } - if (index !== activeIndex && length > 2 && loop) { + if (index !== activeIndex && length > 2 && rootProps.loop) { index = processIndex(index, activeIndex, length); } - if (parentType === 'card') { + if (rootProps.type === 'card') { if (direction.value === 'vertical') { console.warn( `[${CAROUSEL_ITEM_NAME}]: ${CAROUSEL_NAME} vertical direction is not supported in card mode.`, @@ -164,7 +162,7 @@ export default defineComponent({ }; const onClickSlide = () => { - if (parentType === 'card') { + if (rootProps.type === 'card') { const index = slideChildren.value .map((item: CarouselItemData) => item.uid) .indexOf(instance.uid); @@ -175,7 +173,7 @@ export default defineComponent({ onMounted(() => { addItem({ uid: instance.uid, - key: props.key, + itemkey: props.itemkey, states: itemStatus, translateItem, } as CarouselItemData); @@ -191,7 +189,7 @@ export default defineComponent({ v-show={itemReady.value} class={{ [`${prefixCls}-item`]: true, - [`${prefixCls}-item-card`]: parentType === 'card', + [`${prefixCls}-item-card`]: rootProps.type === 'card', 'is-in-stage': itemStatus.inStage, 'is-hover': itemStatus.hover, 'is-active': itemStatus.active, @@ -200,7 +198,7 @@ export default defineComponent({ style={itemStyle.value} onClick={onClickSlide} > - {parentType === 'card' && ( + {rootProps.type === 'card' && (
, default: 'hover', }, type: { @@ -79,6 +74,7 @@ export default defineComponent({ emits: [CHANGE_EVENT], setup(props, { slots, emit, expose }) { useTheme(); + const { prefixCls, wrapperRef, @@ -92,17 +88,13 @@ export default defineComponent({ } = useCarousel(props); const { wrapperClass, carouselStyle } = useCarouselStyle({ + props, prefixCls, - height: props.height, - type: props.type, direction, }); const { startTimer, pauseTimer } = useCarouselPlay({ - interval: props.interval, - initialIndex: props.initialIndex, - autoplay: props.autoplay, - loop: props.loop, + props, activeIndex, slideChildren, }); @@ -164,6 +156,7 @@ export default defineComponent({
( -
    +
    {slideChildren.value.map( (item: CarouselItemData, index: number) => ( -
  • -
  • +
    ), )} -
+
); }, }); diff --git a/components/carousel/interface.ts b/components/carousel/interface.ts index 2069724e..2548d798 100644 --- a/components/carousel/interface.ts +++ b/components/carousel/interface.ts @@ -4,13 +4,14 @@ import type { ExtractPublicPropTypes } from '../_util/interface'; export type Placement = 'top' | 'bottom' | 'left' | 'right'; export type Direction = 'horizontal' | 'vertical' | ''; +export type ArrowType = 'hover' | 'always' | 'never'; export interface CarouselInst extends ReturnType { carouselId?: string; } export const carouselItemProps = { - key: { + itemkey: { type: String, default: '', }, diff --git a/components/carousel/useCarousel.ts b/components/carousel/useCarousel.ts index f29e130b..72fff6ac 100644 --- a/components/carousel/useCarousel.ts +++ b/components/carousel/useCarousel.ts @@ -30,7 +30,7 @@ export default function useCarousel(props: CarouselProps) { }); const itemState = useCarouselItem({ - loop: props.loop, + props, activeIndex, }); @@ -38,9 +38,7 @@ export default function useCarousel(props: CarouselProps) { prefixCls, wrapperRef, direction, - type: props.type, - loop: props.loop, - showArrow: props.showArrow, + rootProps: props, activeIndex, ...itemState, }; diff --git a/components/carousel/useCarouselItem.ts b/components/carousel/useCarouselItem.ts index 519c9537..d0d8055b 100644 --- a/components/carousel/useCarouselItem.ts +++ b/components/carousel/useCarouselItem.ts @@ -1,21 +1,22 @@ import { ref, type Ref } from 'vue'; import { CAROUSEL_NAME } from './const'; import type { CarouselItemData } from './interface'; +import type { CarouselProps } from './carousel'; interface UseCarouselItemType { - loop: boolean; + props: CarouselProps; activeIndex: Ref; } export default function useCarouselItem({ - loop, + props, activeIndex, }: UseCarouselItemType) { // 子项集合 const slideChildren: Ref = ref([]); const resetItemPosition = (oldIndex?: number | unknown): void => { - slideChildren.value.forEach((item, index) => { + slideChildren.value.forEach((item: CarouselItemData, index: number) => { item.translateItem(index, activeIndex.value, oldIndex); }); }; @@ -31,9 +32,9 @@ export default function useCarouselItem({ const childrenCount = slideChildren.value.length; const oldIndex = activeIndex.value; if (index < 0) { - activeIndex.value = loop ? childrenCount - 1 : 0; + activeIndex.value = props.loop ? childrenCount - 1 : 0; } else if (index >= childrenCount) { - activeIndex.value = loop ? 0 : childrenCount - 1; + activeIndex.value = props.loop ? 0 : childrenCount - 1; } else { activeIndex.value = index; } @@ -55,7 +56,9 @@ export default function useCarouselItem({ } function removeItem(uid: number) { - const index = slideChildren.value.findIndex((item) => item.uid === uid); + const index = slideChildren.value.findIndex( + (item: CarouselItemData) => item.uid === uid, + ); if (index !== -1) { slideChildren.value.splice(index, 1); if (activeIndex.value === index) next(); diff --git a/components/carousel/useCarouselPlay.ts b/components/carousel/useCarouselPlay.ts index 59f3afa5..69b6612e 100644 --- a/components/carousel/useCarouselPlay.ts +++ b/components/carousel/useCarouselPlay.ts @@ -1,65 +1,71 @@ import { watch, onMounted, onBeforeUnmount, nextTick, type Ref } from 'vue'; +import type { CarouselProps } from './carousel'; interface UseCarouselPlayType { - loop: boolean; - autoplay: boolean; - interval: number; - initialIndex: number; + props: CarouselProps; activeIndex: Ref; slideChildren: Ref; } // control play -export default ({ - loop, - autoplay, - interval, - initialIndex, - activeIndex, - slideChildren, -}: UseCarouselPlayType) => { +export default ({ props, activeIndex, slideChildren }: UseCarouselPlayType) => { const play = () => { if (activeIndex.value < slideChildren.value.length - 1) { activeIndex.value = activeIndex.value + 1; - } else if (loop) { + } else if (props.loop) { activeIndex.value = 0; } }; let playTimer: number = null; const startTimer = () => { - if (interval <= 0 || !autoplay || playTimer) return; - playTimer = window.setInterval(play, interval); + if (props.interval <= 0 || !props.autoplay || playTimer) return; + playTimer = window.setInterval(play, props.interval); }; + // 暂停定时器 const pauseTimer = () => { clearInterval(playTimer); playTimer = null; }; + // 清除定时器 + const clearTimer = () => { + if (playTimer) pauseTimer(); + }; + + // 监听是否自动播放 watch( - () => autoplay, + () => props.autoplay, (current) => { - // eslint-disable-next-line no-unused-expressions current ? startTimer() : pauseTimer(); }, ); + // 监听间隔时间变化,重新调整自动切换时间 + watch( + () => props.interval, + () => { + clearTimer(); + startTimer(); + }, + ); + // lifecycle onMounted(() => { nextTick(() => { if ( - initialIndex >= 0 && - initialIndex < slideChildren.value.length + props.initialIndex >= 0 && + props.initialIndex < slideChildren.value.length ) { - activeIndex.value = initialIndex; + activeIndex.value = props.initialIndex; } startTimer(); }); }); onBeforeUnmount(() => { - pauseTimer(); + clearTimer(); }); return { diff --git a/components/carousel/useCarouselStyle.ts b/components/carousel/useCarouselStyle.ts index 1f955486..ee65a322 100644 --- a/components/carousel/useCarouselStyle.ts +++ b/components/carousel/useCarouselStyle.ts @@ -1,29 +1,25 @@ -import { computed, type ComputedRef } from 'vue'; +import { computed } from 'vue'; +import type { ComputedRef } from 'vue'; import type { Direction } from './interface'; +import type { CarouselProps } from './carousel'; interface UseCarouselStyleType { + props: CarouselProps; prefixCls: string; - height: string; - type: string; direction: ComputedRef; } -export default ({ - prefixCls, - height, - type, - direction, -}: UseCarouselStyleType) => { +export default ({ props, prefixCls, direction }: UseCarouselStyleType) => { const wrapperClass = computed(() => { const classes = [prefixCls, `${prefixCls}-${direction.value}`]; - if (type === 'card') { + if (props.type === 'card') { classes.push(`${prefixCls}-card`); } return classes; }); const carouselStyle = computed(() => { - const style = { height }; + const style = { height: props.height }; return style; }); diff --git a/docs/.vitepress/components/carousel/default.vue b/docs/.vitepress/components/carousel/default.vue index 60f8ea8d..96498f8f 100644 --- a/docs/.vitepress/components/carousel/default.vue +++ b/docs/.vitepress/components/carousel/default.vue @@ -25,20 +25,10 @@ -