mirror of
https://github.com/element-plus/element-plus.git
synced 2024-11-27 02:01:15 +08:00
refactor(components): [carousel] (#10188)
Co-authored-by: JeremyWuuuuu <15975785+JeremyWuuuuu@users.noreply.github.com>
This commit is contained in:
parent
9285109a0c
commit
904605587f
@ -5,7 +5,7 @@ import Carousel from '../src/carousel.vue'
|
|||||||
import CarouselItem from '../src/carousel-item.vue'
|
import CarouselItem from '../src/carousel-item.vue'
|
||||||
|
|
||||||
import type { VueWrapper } from '@vue/test-utils'
|
import type { VueWrapper } from '@vue/test-utils'
|
||||||
import type { CarouselInstance } from '../src/carousel'
|
import type { CarouselInstance } from '../src/instance'
|
||||||
|
|
||||||
const wait = (ms = 100) =>
|
const wait = (ms = 100) =>
|
||||||
new Promise((resolve) => setTimeout(() => resolve(0), ms))
|
new Promise((resolve) => setTimeout(() => resolve(0), ms))
|
||||||
|
@ -12,3 +12,5 @@ export const ElCarouselItem = withNoopInstall(CarouselItem)
|
|||||||
|
|
||||||
export * from './src/carousel'
|
export * from './src/carousel'
|
||||||
export * from './src/carousel-item'
|
export * from './src/carousel-item'
|
||||||
|
|
||||||
|
export type { CarouselInstance } from './src/instance'
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { buildProps, isNumber } from '@element-plus/utils'
|
import { buildProps, isNumber } from '@element-plus/utils'
|
||||||
import type { ExtractPropTypes } from 'vue'
|
import type { ExtractPropTypes } from 'vue'
|
||||||
import type Carousel from './carousel.vue'
|
|
||||||
|
|
||||||
export const carouselProps = buildProps({
|
export const carouselProps = buildProps({
|
||||||
initialIndex: {
|
initialIndex: {
|
||||||
@ -64,5 +63,3 @@ export const carouselEmits = {
|
|||||||
|
|
||||||
export type CarouselProps = ExtractPropTypes<typeof carouselProps>
|
export type CarouselProps = ExtractPropTypes<typeof carouselProps>
|
||||||
export type CarouselEmits = typeof carouselEmits
|
export type CarouselEmits = typeof carouselEmits
|
||||||
|
|
||||||
export type CarouselInstance = InstanceType<typeof Carousel>
|
|
||||||
|
@ -62,60 +62,39 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import {
|
import { computed, unref } from 'vue'
|
||||||
computed,
|
|
||||||
getCurrentInstance,
|
|
||||||
onBeforeUnmount,
|
|
||||||
onMounted,
|
|
||||||
provide,
|
|
||||||
ref,
|
|
||||||
shallowRef,
|
|
||||||
unref,
|
|
||||||
watch,
|
|
||||||
} from 'vue'
|
|
||||||
import { throttle } from 'lodash-unified'
|
|
||||||
import { useResizeObserver } from '@vueuse/core'
|
|
||||||
import { debugWarn, isString } from '@element-plus/utils'
|
|
||||||
import { ElIcon } from '@element-plus/components/icon'
|
import { ElIcon } from '@element-plus/components/icon'
|
||||||
import { ArrowLeft, ArrowRight } from '@element-plus/icons-vue'
|
import { ArrowLeft, ArrowRight } from '@element-plus/icons-vue'
|
||||||
import { useNamespace, useOrderedChildren } from '@element-plus/hooks'
|
import { useNamespace } from '@element-plus/hooks'
|
||||||
import { carouselContextKey } from '@element-plus/tokens'
|
|
||||||
import { carouselEmits, carouselProps } from './carousel'
|
import { carouselEmits, carouselProps } from './carousel'
|
||||||
import type { CarouselItemContext } from '@element-plus/tokens'
|
import { useCarousel } from './use-carousel'
|
||||||
|
|
||||||
|
const COMPONENT_NAME = 'ElCarousel'
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'ElCarousel',
|
name: COMPONENT_NAME,
|
||||||
})
|
})
|
||||||
|
|
||||||
const props = defineProps(carouselProps)
|
const props = defineProps(carouselProps)
|
||||||
const emit = defineEmits(carouselEmits)
|
const emit = defineEmits(carouselEmits)
|
||||||
const ns = useNamespace('carousel')
|
|
||||||
const COMPONENT_NAME = 'ElCarousel'
|
|
||||||
const THROTTLE_TIME = 300
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
children: items,
|
activeIndex,
|
||||||
addChild: addItem,
|
arrowDisplay,
|
||||||
removeChild: removeItem,
|
hasLabel,
|
||||||
} = useOrderedChildren<CarouselItemContext>(
|
hover,
|
||||||
getCurrentInstance()!,
|
isCardType,
|
||||||
'ElCarouselItem'
|
items,
|
||||||
)
|
handleButtonEnter,
|
||||||
|
handleButtonLeave,
|
||||||
// refs
|
handleIndicatorClick,
|
||||||
const activeIndex = ref(-1)
|
handleMouseEnter,
|
||||||
const timer = ref<ReturnType<typeof setInterval> | null>(null)
|
handleMouseLeave,
|
||||||
const hover = ref(false)
|
setActiveItem,
|
||||||
const root = ref<HTMLDivElement>()
|
prev,
|
||||||
|
next,
|
||||||
// computed
|
throttledArrowClick,
|
||||||
const arrowDisplay = computed(
|
throttledIndicatorHover,
|
||||||
() => props.arrow !== 'never' && !unref(isVertical)
|
} = useCarousel(props, emit, COMPONENT_NAME)
|
||||||
)
|
const ns = useNamespace('carousel')
|
||||||
|
|
||||||
const hasLabel = computed(() => {
|
|
||||||
return items.value.some((item) => item.props.label.toString().length > 0)
|
|
||||||
})
|
|
||||||
|
|
||||||
const carouselClasses = computed(() => {
|
const carouselClasses = computed(() => {
|
||||||
const classes = [ns.b(), ns.m(props.direction)]
|
const classes = [ns.b(), ns.m(props.direction)]
|
||||||
@ -127,7 +106,7 @@ const carouselClasses = computed(() => {
|
|||||||
|
|
||||||
const indicatorsClasses = computed(() => {
|
const indicatorsClasses = computed(() => {
|
||||||
const classes = [ns.e('indicators'), ns.em('indicators', props.direction)]
|
const classes = [ns.e('indicators'), ns.em('indicators', props.direction)]
|
||||||
if (hasLabel.value) {
|
if (unref(hasLabel)) {
|
||||||
classes.push(ns.em('indicators', 'labels'))
|
classes.push(ns.em('indicators', 'labels'))
|
||||||
}
|
}
|
||||||
if (props.indicatorPosition === 'outside' || unref(isCardType)) {
|
if (props.indicatorPosition === 'outside' || unref(isCardType)) {
|
||||||
@ -136,211 +115,6 @@ const indicatorsClasses = computed(() => {
|
|||||||
return classes
|
return classes
|
||||||
})
|
})
|
||||||
|
|
||||||
const isCardType = computed(() => props.type === 'card')
|
|
||||||
const isVertical = computed(() => props.direction === 'vertical')
|
|
||||||
|
|
||||||
// methods
|
|
||||||
const throttledArrowClick = throttle(
|
|
||||||
(index: number) => {
|
|
||||||
setActiveItem(index)
|
|
||||||
},
|
|
||||||
THROTTLE_TIME,
|
|
||||||
{ trailing: true }
|
|
||||||
)
|
|
||||||
|
|
||||||
const throttledIndicatorHover = throttle((index: number) => {
|
|
||||||
handleIndicatorHover(index)
|
|
||||||
}, THROTTLE_TIME)
|
|
||||||
|
|
||||||
function pauseTimer() {
|
|
||||||
if (timer.value) {
|
|
||||||
clearInterval(timer.value)
|
|
||||||
timer.value = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function startTimer() {
|
|
||||||
if (props.interval <= 0 || !props.autoplay || timer.value) return
|
|
||||||
timer.value = setInterval(() => playSlides(), props.interval)
|
|
||||||
}
|
|
||||||
|
|
||||||
const playSlides = () => {
|
|
||||||
if (activeIndex.value < items.value.length - 1) {
|
|
||||||
activeIndex.value = activeIndex.value + 1
|
|
||||||
} else if (props.loop) {
|
|
||||||
activeIndex.value = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function setActiveItem(index: number | string) {
|
|
||||||
if (isString(index)) {
|
|
||||||
const filteredItems = items.value.filter(
|
|
||||||
(item) => item.props.name === index
|
|
||||||
)
|
|
||||||
if (filteredItems.length > 0) {
|
|
||||||
index = items.value.indexOf(filteredItems[0])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
index = Number(index)
|
|
||||||
if (Number.isNaN(index) || index !== Math.floor(index)) {
|
|
||||||
debugWarn(COMPONENT_NAME, 'index must be integer.')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const itemCount = items.value.length
|
|
||||||
const oldIndex = activeIndex.value
|
|
||||||
if (index < 0) {
|
|
||||||
activeIndex.value = props.loop ? itemCount - 1 : 0
|
|
||||||
} else if (index >= itemCount) {
|
|
||||||
activeIndex.value = props.loop ? 0 : itemCount - 1
|
|
||||||
} else {
|
|
||||||
activeIndex.value = index
|
|
||||||
}
|
|
||||||
if (oldIndex === activeIndex.value) {
|
|
||||||
resetItemPosition(oldIndex)
|
|
||||||
}
|
|
||||||
resetTimer()
|
|
||||||
}
|
|
||||||
|
|
||||||
function resetItemPosition(oldIndex?: number) {
|
|
||||||
items.value.forEach((item, index) => {
|
|
||||||
item.translateItem(index, activeIndex.value, oldIndex)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function itemInStage(item: CarouselItemContext, index: number) {
|
|
||||||
const _items = unref(items)
|
|
||||||
const itemCount = _items.length
|
|
||||||
if (itemCount === 0 || !item.states.inStage) return false
|
|
||||||
const nextItemIndex = index + 1
|
|
||||||
const prevItemIndex = index - 1
|
|
||||||
const lastItemIndex = itemCount - 1
|
|
||||||
const isLastItemActive = _items[lastItemIndex].states.active
|
|
||||||
const isFirstItemActive = _items[0].states.active
|
|
||||||
const isNextItemActive = _items[nextItemIndex]?.states?.active
|
|
||||||
const isPrevItemActive = _items[prevItemIndex]?.states?.active
|
|
||||||
|
|
||||||
if ((index === lastItemIndex && isFirstItemActive) || isNextItemActive) {
|
|
||||||
return 'left'
|
|
||||||
} else if ((index === 0 && isLastItemActive) || isPrevItemActive) {
|
|
||||||
return 'right'
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleMouseEnter() {
|
|
||||||
hover.value = true
|
|
||||||
if (props.pauseOnHover) {
|
|
||||||
pauseTimer()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleMouseLeave() {
|
|
||||||
hover.value = false
|
|
||||||
startTimer()
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleButtonEnter(arrow: 'left' | 'right') {
|
|
||||||
if (unref(isVertical)) return
|
|
||||||
items.value.forEach((item, index) => {
|
|
||||||
if (arrow === itemInStage(item, index)) {
|
|
||||||
item.states.hover = true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleButtonLeave() {
|
|
||||||
if (unref(isVertical)) return
|
|
||||||
items.value.forEach((item) => {
|
|
||||||
item.states.hover = false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleIndicatorClick(index: number) {
|
|
||||||
activeIndex.value = index
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleIndicatorHover(index: number) {
|
|
||||||
if (props.trigger === 'hover' && index !== activeIndex.value) {
|
|
||||||
activeIndex.value = index
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function prev() {
|
|
||||||
setActiveItem(activeIndex.value - 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
function next() {
|
|
||||||
setActiveItem(activeIndex.value + 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
function resetTimer() {
|
|
||||||
pauseTimer()
|
|
||||||
startTimer()
|
|
||||||
}
|
|
||||||
|
|
||||||
// watch
|
|
||||||
watch(
|
|
||||||
() => activeIndex.value,
|
|
||||||
(current, prev) => {
|
|
||||||
resetItemPosition(prev)
|
|
||||||
if (prev > -1) {
|
|
||||||
emit('change', current, prev)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
watch(
|
|
||||||
() => props.autoplay,
|
|
||||||
(autoplay) => {
|
|
||||||
autoplay ? startTimer() : pauseTimer()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
watch(
|
|
||||||
() => props.loop,
|
|
||||||
() => {
|
|
||||||
setActiveItem(activeIndex.value)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => props.interval,
|
|
||||||
() => {
|
|
||||||
resetTimer()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => items.value,
|
|
||||||
() => {
|
|
||||||
if (items.value.length > 0) setActiveItem(props.initialIndex)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
const resizeObserver = shallowRef<ReturnType<typeof useResizeObserver>>()
|
|
||||||
// lifecycle
|
|
||||||
onMounted(() => {
|
|
||||||
resizeObserver.value = useResizeObserver(root.value, () => {
|
|
||||||
resetItemPosition()
|
|
||||||
})
|
|
||||||
startTimer()
|
|
||||||
})
|
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
|
||||||
pauseTimer()
|
|
||||||
if (root.value && resizeObserver.value) resizeObserver.value.stop()
|
|
||||||
})
|
|
||||||
|
|
||||||
// provide
|
|
||||||
provide(carouselContextKey, {
|
|
||||||
root,
|
|
||||||
isCardType,
|
|
||||||
isVertical,
|
|
||||||
items,
|
|
||||||
loop: props.loop,
|
|
||||||
addItem,
|
|
||||||
removeItem,
|
|
||||||
setActiveItem,
|
|
||||||
})
|
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
/** @description manually switch slide */
|
/** @description manually switch slide */
|
||||||
setActiveItem,
|
setActiveItem,
|
||||||
|
3
packages/components/carousel/src/instance.ts
Normal file
3
packages/components/carousel/src/instance.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import type Carousel from './carousel.vue'
|
||||||
|
|
||||||
|
export type CarouselInstance = InstanceType<typeof Carousel>
|
276
packages/components/carousel/src/use-carousel.ts
Normal file
276
packages/components/carousel/src/use-carousel.ts
Normal file
@ -0,0 +1,276 @@
|
|||||||
|
import {
|
||||||
|
computed,
|
||||||
|
getCurrentInstance,
|
||||||
|
onBeforeUnmount,
|
||||||
|
onMounted,
|
||||||
|
provide,
|
||||||
|
ref,
|
||||||
|
shallowRef,
|
||||||
|
unref,
|
||||||
|
watch,
|
||||||
|
} from 'vue'
|
||||||
|
import { throttle } from 'lodash-unified'
|
||||||
|
import { useResizeObserver } from '@vueuse/core'
|
||||||
|
import { debugWarn, isString } from '@element-plus/utils'
|
||||||
|
import { carouselContextKey } from '@element-plus/tokens'
|
||||||
|
import { useOrderedChildren } from '@element-plus/hooks'
|
||||||
|
|
||||||
|
import type { SetupContext } from 'vue'
|
||||||
|
import type { CarouselItemContext } from '@element-plus/tokens'
|
||||||
|
import type { CarouselEmits, CarouselProps } from './carousel'
|
||||||
|
|
||||||
|
const THROTTLE_TIME = 300
|
||||||
|
|
||||||
|
export const useCarousel = (
|
||||||
|
props: CarouselProps,
|
||||||
|
emit: SetupContext<CarouselEmits>['emit'],
|
||||||
|
componentName: string
|
||||||
|
) => {
|
||||||
|
const {
|
||||||
|
children: items,
|
||||||
|
addChild: addItem,
|
||||||
|
removeChild: removeItem,
|
||||||
|
} = useOrderedChildren<CarouselItemContext>(
|
||||||
|
getCurrentInstance()!,
|
||||||
|
'ElCarouselItem'
|
||||||
|
)
|
||||||
|
|
||||||
|
// refs
|
||||||
|
const activeIndex = ref(-1)
|
||||||
|
const timer = ref<ReturnType<typeof setInterval> | null>(null)
|
||||||
|
const hover = ref(false)
|
||||||
|
const root = ref<HTMLDivElement>()
|
||||||
|
|
||||||
|
// computed
|
||||||
|
const arrowDisplay = computed(
|
||||||
|
() => props.arrow !== 'never' && !unref(isVertical)
|
||||||
|
)
|
||||||
|
|
||||||
|
const hasLabel = computed(() => {
|
||||||
|
return items.value.some((item) => item.props.label.toString().length > 0)
|
||||||
|
})
|
||||||
|
|
||||||
|
const isCardType = computed(() => props.type === 'card')
|
||||||
|
const isVertical = computed(() => props.direction === 'vertical')
|
||||||
|
|
||||||
|
// methods
|
||||||
|
const throttledArrowClick = throttle(
|
||||||
|
(index: number) => {
|
||||||
|
setActiveItem(index)
|
||||||
|
},
|
||||||
|
THROTTLE_TIME,
|
||||||
|
{ trailing: true }
|
||||||
|
)
|
||||||
|
|
||||||
|
const throttledIndicatorHover = throttle((index: number) => {
|
||||||
|
handleIndicatorHover(index)
|
||||||
|
}, THROTTLE_TIME)
|
||||||
|
|
||||||
|
function pauseTimer() {
|
||||||
|
if (timer.value) {
|
||||||
|
clearInterval(timer.value)
|
||||||
|
timer.value = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function startTimer() {
|
||||||
|
if (props.interval <= 0 || !props.autoplay || timer.value) return
|
||||||
|
timer.value = setInterval(() => playSlides(), props.interval)
|
||||||
|
}
|
||||||
|
|
||||||
|
const playSlides = () => {
|
||||||
|
if (activeIndex.value < items.value.length - 1) {
|
||||||
|
activeIndex.value = activeIndex.value + 1
|
||||||
|
} else if (props.loop) {
|
||||||
|
activeIndex.value = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setActiveItem(index: number | string) {
|
||||||
|
if (isString(index)) {
|
||||||
|
const filteredItems = items.value.filter(
|
||||||
|
(item) => item.props.name === index
|
||||||
|
)
|
||||||
|
if (filteredItems.length > 0) {
|
||||||
|
index = items.value.indexOf(filteredItems[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
index = Number(index)
|
||||||
|
if (Number.isNaN(index) || index !== Math.floor(index)) {
|
||||||
|
debugWarn(componentName, 'index must be integer.')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const itemCount = items.value.length
|
||||||
|
const oldIndex = activeIndex.value
|
||||||
|
if (index < 0) {
|
||||||
|
activeIndex.value = props.loop ? itemCount - 1 : 0
|
||||||
|
} else if (index >= itemCount) {
|
||||||
|
activeIndex.value = props.loop ? 0 : itemCount - 1
|
||||||
|
} else {
|
||||||
|
activeIndex.value = index
|
||||||
|
}
|
||||||
|
if (oldIndex === activeIndex.value) {
|
||||||
|
resetItemPosition(oldIndex)
|
||||||
|
}
|
||||||
|
resetTimer()
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetItemPosition(oldIndex?: number) {
|
||||||
|
items.value.forEach((item, index) => {
|
||||||
|
item.translateItem(index, activeIndex.value, oldIndex)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function itemInStage(item: CarouselItemContext, index: number) {
|
||||||
|
const _items = unref(items)
|
||||||
|
const itemCount = _items.length
|
||||||
|
if (itemCount === 0 || !item.states.inStage) return false
|
||||||
|
const nextItemIndex = index + 1
|
||||||
|
const prevItemIndex = index - 1
|
||||||
|
const lastItemIndex = itemCount - 1
|
||||||
|
const isLastItemActive = _items[lastItemIndex].states.active
|
||||||
|
const isFirstItemActive = _items[0].states.active
|
||||||
|
const isNextItemActive = _items[nextItemIndex]?.states?.active
|
||||||
|
const isPrevItemActive = _items[prevItemIndex]?.states?.active
|
||||||
|
|
||||||
|
if ((index === lastItemIndex && isFirstItemActive) || isNextItemActive) {
|
||||||
|
return 'left'
|
||||||
|
} else if ((index === 0 && isLastItemActive) || isPrevItemActive) {
|
||||||
|
return 'right'
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMouseEnter() {
|
||||||
|
hover.value = true
|
||||||
|
if (props.pauseOnHover) {
|
||||||
|
pauseTimer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMouseLeave() {
|
||||||
|
hover.value = false
|
||||||
|
startTimer()
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleButtonEnter(arrow: 'left' | 'right') {
|
||||||
|
if (unref(isVertical)) return
|
||||||
|
items.value.forEach((item, index) => {
|
||||||
|
if (arrow === itemInStage(item, index)) {
|
||||||
|
item.states.hover = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleButtonLeave() {
|
||||||
|
if (unref(isVertical)) return
|
||||||
|
items.value.forEach((item) => {
|
||||||
|
item.states.hover = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleIndicatorClick(index: number) {
|
||||||
|
activeIndex.value = index
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleIndicatorHover(index: number) {
|
||||||
|
if (props.trigger === 'hover' && index !== activeIndex.value) {
|
||||||
|
activeIndex.value = index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function prev() {
|
||||||
|
setActiveItem(activeIndex.value - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
function next() {
|
||||||
|
setActiveItem(activeIndex.value + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetTimer() {
|
||||||
|
pauseTimer()
|
||||||
|
startTimer()
|
||||||
|
}
|
||||||
|
|
||||||
|
// watch
|
||||||
|
watch(
|
||||||
|
() => activeIndex.value,
|
||||||
|
(current, prev) => {
|
||||||
|
resetItemPosition(prev)
|
||||||
|
if (prev > -1) {
|
||||||
|
emit('change', current, prev)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
watch(
|
||||||
|
() => props.autoplay,
|
||||||
|
(autoplay) => {
|
||||||
|
autoplay ? startTimer() : pauseTimer()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
watch(
|
||||||
|
() => props.loop,
|
||||||
|
() => {
|
||||||
|
setActiveItem(activeIndex.value)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.interval,
|
||||||
|
() => {
|
||||||
|
resetTimer()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => items.value,
|
||||||
|
() => {
|
||||||
|
if (items.value.length > 0) setActiveItem(props.initialIndex)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const resizeObserver = shallowRef<ReturnType<typeof useResizeObserver>>()
|
||||||
|
// lifecycle
|
||||||
|
onMounted(() => {
|
||||||
|
resizeObserver.value = useResizeObserver(root.value, () => {
|
||||||
|
resetItemPosition()
|
||||||
|
})
|
||||||
|
startTimer()
|
||||||
|
})
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
pauseTimer()
|
||||||
|
if (root.value && resizeObserver.value) resizeObserver.value.stop()
|
||||||
|
})
|
||||||
|
|
||||||
|
// provide
|
||||||
|
provide(carouselContextKey, {
|
||||||
|
root,
|
||||||
|
isCardType,
|
||||||
|
isVertical,
|
||||||
|
items,
|
||||||
|
loop: props.loop,
|
||||||
|
addItem,
|
||||||
|
removeItem,
|
||||||
|
setActiveItem,
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
activeIndex,
|
||||||
|
arrowDisplay,
|
||||||
|
hasLabel,
|
||||||
|
hover,
|
||||||
|
isCardType,
|
||||||
|
items,
|
||||||
|
handleButtonEnter,
|
||||||
|
handleButtonLeave,
|
||||||
|
handleIndicatorClick,
|
||||||
|
handleMouseEnter,
|
||||||
|
handleMouseLeave,
|
||||||
|
setActiveItem,
|
||||||
|
prev,
|
||||||
|
next,
|
||||||
|
throttledArrowClick,
|
||||||
|
throttledIndicatorHover,
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user