From af5ab80b1539a317c370d435e11686b60c87504e Mon Sep 17 00:00:00 2001 From: erictang Date: Thu, 28 Mar 2024 19:54:44 +0800 Subject: [PATCH 1/3] =?UTF-8?q?refactor(carousel):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E5=B1=9E=E6=80=A7=E5=93=8D=E5=BA=94=E6=94=AF=E6=8C=81=E3=80=81?= =?UTF-8?q?=E5=AE=8C=E5=96=84=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/carousel/arrow.tsx | 42 +++++---- components/carousel/carousel-item.tsx | 17 ++-- components/carousel/carousel.tsx | 23 ++--- components/carousel/indicator.tsx | 8 +- components/carousel/interface.ts | 3 +- components/carousel/useCarousel.ts | 9 +- components/carousel/useCarouselItem.ts | 15 ++-- components/carousel/useCarouselPlay.ts | 30 +++---- components/carousel/useCarouselStyle.ts | 18 ++-- .../components/carousel/default.vue | 87 ++++++++++++++++--- 10 files changed, 145 insertions(+), 107 deletions(-) diff --git a/components/carousel/arrow.tsx b/components/carousel/arrow.tsx index abd29300..8c5583c8 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,36 @@ export default defineComponent({ type: Boolean, required: true, }, + showArrow: { + type: String as PropType, + default: 'hover', + }, + loop: { + type: Boolean, + default: true, + }, activeIndex: Number, } satisfies ComponentObjectPropsOptions, setup(props) { - const { - prefixCls, - direction, - slideChildren, - showArrow, - loop, - setActiveItem, - } = inject(provideKey); + const { prefixCls, direction, slideChildren, 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) && + (props.loop || props.activeIndex > 0), ); const arrowRightShow = computed( () => - (showArrow === 'always' || props.hover) && - (loop || props.activeIndex < slideChildren.value.length - 1), + (props.showArrow === 'always' || props.hover) && + (props.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..69b2747e 100644 --- a/components/carousel/carousel-item.tsx +++ b/components/carousel/carousel-item.tsx @@ -59,7 +59,7 @@ export default defineComponent({ prefixCls, direction, wrapperRef, - type: parentType, + parentType, loop, slideChildren, setActiveItem, @@ -130,16 +130,15 @@ export default defineComponent({ oldIndex: number, ) => { const length = slideChildren.value.length; - // eslint-disable-next-line no-undefined - if (parentType !== 'card' && oldIndex !== undefined) { + if (parentType.value !== 'card' && oldIndex !== undefined) { itemStatus.animating = index === activeIndex || index === oldIndex; } - if (index !== activeIndex && length > 2 && loop) { + if (index !== activeIndex && length > 2 && loop.value) { index = processIndex(index, activeIndex, length); } - if (parentType === 'card') { + if (parentType.value === 'card') { if (direction.value === 'vertical') { console.warn( `[${CAROUSEL_ITEM_NAME}]: ${CAROUSEL_NAME} vertical direction is not supported in card mode.`, @@ -164,7 +163,7 @@ export default defineComponent({ }; const onClickSlide = () => { - if (parentType === 'card') { + if (parentType.value === 'card') { const index = slideChildren.value .map((item: CarouselItemData) => item.uid) .indexOf(instance.uid); @@ -175,7 +174,7 @@ export default defineComponent({ onMounted(() => { addItem({ uid: instance.uid, - key: props.key, + itemkey: props.itemkey, states: itemStatus, translateItem, } as CarouselItemData); @@ -191,7 +190,7 @@ export default defineComponent({ v-show={itemReady.value} class={{ [`${prefixCls}-item`]: true, - [`${prefixCls}-item-card`]: parentType === 'card', + [`${prefixCls}-item-card`]: parentType.value === 'card', 'is-in-stage': itemStatus.inStage, 'is-hover': itemStatus.hover, 'is-active': itemStatus.active, @@ -200,7 +199,7 @@ export default defineComponent({ style={itemStyle.value} onClick={onClickSlide} > - {parentType === 'card' && ( + {parentType.value === '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..a51bb277 100644 --- a/components/carousel/useCarousel.ts +++ b/components/carousel/useCarousel.ts @@ -1,4 +1,4 @@ -import { ref, computed, provide } from 'vue'; +import { ref, toRef, computed, provide } from 'vue'; import getPrefixCls from '../_util/getPrefixCls'; import { provideKey } from './const'; import useCarouselItem from './useCarouselItem'; @@ -30,7 +30,7 @@ export default function useCarousel(props: CarouselProps) { }); const itemState = useCarouselItem({ - loop: props.loop, + props, activeIndex, }); @@ -38,9 +38,8 @@ export default function useCarousel(props: CarouselProps) { prefixCls, wrapperRef, direction, - type: props.type, - loop: props.loop, - showArrow: props.showArrow, + parentType: toRef(props.type), + loop: toRef(props.loop), 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..e70a711b 100644 --- a/components/carousel/useCarouselPlay.ts +++ b/components/carousel/useCarouselPlay.ts @@ -1,35 +1,26 @@ 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 = () => { @@ -38,9 +29,8 @@ export default ({ }; watch( - () => autoplay, + () => props.autoplay, (current) => { - // eslint-disable-next-line no-unused-expressions current ? startTimer() : pauseTimer(); }, ); @@ -49,10 +39,10 @@ export default ({ 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(); }); 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..5199caf5 100644 --- a/docs/.vitepress/components/carousel/default.vue +++ b/docs/.vitepress/components/carousel/default.vue @@ -1,6 +1,68 @@ - From cd1ee1b40739580ff0096832b0ef8a9dfb34e789 Mon Sep 17 00:00:00 2001 From: erictang Date: Fri, 29 Mar 2024 16:35:49 +0800 Subject: [PATCH 3/3] =?UTF-8?q?fix(carousel):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E7=AE=AD=E5=A4=B4loop=E5=8F=82=E6=95=B0=E5=A4=B1=E6=95=88?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/carousel/arrow.tsx | 17 +++++++++-------- components/carousel/carousel-item.tsx | 15 +++++++-------- components/carousel/useCarousel.ts | 3 +-- 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/components/carousel/arrow.tsx b/components/carousel/arrow.tsx index 8c5583c8..51718307 100644 --- a/components/carousel/arrow.tsx +++ b/components/carousel/arrow.tsx @@ -20,15 +20,16 @@ export default defineComponent({ type: String as PropType, default: 'hover', }, - loop: { - type: Boolean, - default: true, - }, activeIndex: Number, } satisfies ComponentObjectPropsOptions, setup(props) { - const { prefixCls, direction, slideChildren, setActiveItem } = - inject(provideKey); + const { + prefixCls, + direction, + rootProps, + slideChildren, + setActiveItem, + } = inject(provideKey); const arrowVisible = computed( () => @@ -38,13 +39,13 @@ export default defineComponent({ const arrowLeftShow = computed( () => (props.showArrow === 'always' || props.hover) && - (props.loop || props.activeIndex > 0), + (rootProps.loop || props.activeIndex > 0), ); const arrowRightShow = computed( () => (props.showArrow === 'always' || props.hover) && - (props.loop || + (rootProps.loop || props.activeIndex < slideChildren.value.length - 1), ); diff --git a/components/carousel/carousel-item.tsx b/components/carousel/carousel-item.tsx index 69b2747e..3eda1ce5 100644 --- a/components/carousel/carousel-item.tsx +++ b/components/carousel/carousel-item.tsx @@ -59,8 +59,7 @@ export default defineComponent({ prefixCls, direction, wrapperRef, - parentType, - loop, + rootProps, slideChildren, setActiveItem, addItem, @@ -130,15 +129,15 @@ export default defineComponent({ oldIndex: number, ) => { const length = slideChildren.value.length; - if (parentType.value !== 'card' && oldIndex !== undefined) { + if (rootProps.type !== 'card' && oldIndex !== undefined) { itemStatus.animating = index === activeIndex || index === oldIndex; } - if (index !== activeIndex && length > 2 && loop.value) { + if (index !== activeIndex && length > 2 && rootProps.loop) { index = processIndex(index, activeIndex, length); } - if (parentType.value === 'card') { + if (rootProps.type === 'card') { if (direction.value === 'vertical') { console.warn( `[${CAROUSEL_ITEM_NAME}]: ${CAROUSEL_NAME} vertical direction is not supported in card mode.`, @@ -163,7 +162,7 @@ export default defineComponent({ }; const onClickSlide = () => { - if (parentType.value === 'card') { + if (rootProps.type === 'card') { const index = slideChildren.value .map((item: CarouselItemData) => item.uid) .indexOf(instance.uid); @@ -190,7 +189,7 @@ export default defineComponent({ v-show={itemReady.value} class={{ [`${prefixCls}-item`]: true, - [`${prefixCls}-item-card`]: parentType.value === 'card', + [`${prefixCls}-item-card`]: rootProps.type === 'card', 'is-in-stage': itemStatus.inStage, 'is-hover': itemStatus.hover, 'is-active': itemStatus.active, @@ -199,7 +198,7 @@ export default defineComponent({ style={itemStyle.value} onClick={onClickSlide} > - {parentType.value === 'card' && ( + {rootProps.type === 'card' && (
props.type), - loop: computed(() => props.loop), + rootProps: props, activeIndex, ...itemState, };