Skip to content

Commit

Permalink
refactor(components): [carousel-item] (#10219)
Browse files Browse the repository at this point in the history
Co-authored-by: JeremyWuuuuu <15975785+JeremyWuuuuu@users.noreply.github.com>
  • Loading branch information
jw-foss and jw-foss committed Oct 26, 2022
1 parent a7df718 commit bfb8e26
Show file tree
Hide file tree
Showing 5 changed files with 190 additions and 153 deletions.
2 changes: 1 addition & 1 deletion packages/components/carousel/index.ts
Expand Up @@ -13,4 +13,4 @@ export const ElCarouselItem = withNoopInstall(CarouselItem)
export * from './src/carousel'
export * from './src/carousel-item'

export type { CarouselInstance } from './src/instance'
export type { CarouselInstance, CarouselItemInstance } from './src/instance'
3 changes: 0 additions & 3 deletions packages/components/carousel/src/carousel-item.ts
@@ -1,6 +1,5 @@
import { buildProps } from '@element-plus/utils'
import type { ExtractPropTypes } from 'vue'
import type CarouselItem from './carousel-item.vue'

export const carouselItemProps = buildProps({
name: { type: String, default: '' },
Expand All @@ -11,5 +10,3 @@ export const carouselItemProps = buildProps({
} as const)

export type CarouselItemProps = ExtractPropTypes<typeof carouselItemProps>

export type CarouselItemInstance = InstanceType<typeof CarouselItem>
163 changes: 14 additions & 149 deletions packages/components/carousel/src/carousel-item.vue
Expand Up @@ -18,20 +18,10 @@
</template>

<script lang="ts" setup>
import {
computed,
getCurrentInstance,
inject,
onMounted,
onUnmounted,
reactive,
ref,
unref,
} from 'vue'
import { debugWarn, isUndefined } from '@element-plus/utils'
import { computed, unref } from 'vue'
import { useNamespace } from '@element-plus/hooks'
import { carouselContextKey } from '@element-plus/tokens'
import { carouselItemProps } from './carousel-item'
import { useCarouselItem } from './use-carousel-item'
import type { CSSProperties } from 'vue'
Expand All @@ -43,35 +33,18 @@ const props = defineProps(carouselItemProps)
const ns = useNamespace('carousel')
const COMPONENT_NAME = 'ElCarouselItem'
// inject
const carouselContext = inject(carouselContextKey)!
// instance
const instance = getCurrentInstance()!
if (!carouselContext) {
debugWarn(
COMPONENT_NAME,
'usage: <el-carousel></el-carousel-item></el-carousel>'
)
}
if (!instance) {
debugWarn(
COMPONENT_NAME,
'compositional hook can only be invoked inside setups'
)
}
const CARD_SCALE = 0.83
const hover = ref(false)
const translate = ref(0)
const scale = ref(1)
const active = ref(false)
const ready = ref(false)
const inStage = ref(false)
const animating = ref(false)
// computed
const { isCardType, isVertical } = carouselContext
const {
active,
animating,
hover,
inStage,
isVertical,
translate,
isCardType,
scale,
ready,
handleItemClick,
} = useCarouselItem(props, COMPONENT_NAME)
const itemStyle = computed<CSSProperties>(() => {
const translateType = `translate${unref(isVertical) ? 'Y' : 'X'}`
Expand All @@ -83,112 +56,4 @@ const itemStyle = computed<CSSProperties>(() => {
transform,
}
})
// methods
function processIndex(index: number, activeIndex: number, length: number) {
const lastItemIndex = length - 1
const prevItemIndex = activeIndex - 1
const nextItemIndex = activeIndex + 1
const halfItemIndex = length / 2
if (activeIndex === 0 && index === lastItemIndex) {
return -1
} else if (activeIndex === lastItemIndex && index === 0) {
return length
} else if (index < prevItemIndex && activeIndex - index >= halfItemIndex) {
return length + 1
} else if (index > nextItemIndex && index - activeIndex >= halfItemIndex) {
return -2
}
return index
}
function calcCardTranslate(index: number, activeIndex: number) {
const parentWidth = carouselContext.root.value?.offsetWidth || 0
if (inStage.value) {
return (parentWidth * ((2 - CARD_SCALE) * (index - activeIndex) + 1)) / 4
} else if (index < activeIndex) {
return (-(1 + CARD_SCALE) * parentWidth) / 4
} else {
return ((3 + CARD_SCALE) * parentWidth) / 4
}
}
function calcTranslate(
index: number,
activeIndex: number,
isVertical: boolean
) {
const rootEl = carouselContext.root.value
if (!rootEl) return 0
const distance = (isVertical ? rootEl.offsetHeight : rootEl.offsetWidth) || 0
return distance * (index - activeIndex)
}
const translateItem = (
index: number,
activeIndex: number,
oldIndex?: number
) => {
const _isCardType = unref(isCardType)
const carouselItemLength = carouselContext.items.value.length ?? Number.NaN
const isActive = index === activeIndex
if (!_isCardType && !isUndefined(oldIndex)) {
animating.value = isActive || index === oldIndex
}
if (!isActive && carouselItemLength > 2 && carouselContext.loop) {
index = processIndex(index, activeIndex, carouselItemLength)
}
const _isVertical = unref(isVertical)
active.value = isActive
if (_isCardType) {
if (_isVertical) {
debugWarn('Carousel', 'vertical direction is not supported for card mode')
}
inStage.value = Math.round(Math.abs(index - activeIndex)) <= 1
translate.value = calcCardTranslate(index, activeIndex)
scale.value = unref(active) ? 1 : CARD_SCALE
} else {
translate.value = calcTranslate(index, activeIndex, _isVertical)
}
ready.value = true
}
function handleItemClick() {
if (carouselContext && unref(isCardType)) {
const index = carouselContext.items.value.findIndex(
({ uid }) => uid === instance.uid
)
carouselContext.setActiveItem(index)
}
}
// lifecycle
onMounted(() => {
carouselContext.addItem({
props,
states: reactive({
hover,
translate,
scale,
active,
ready,
inStage,
animating,
}),
uid: instance.uid,
translateItem,
})
})
onUnmounted(() => {
carouselContext.removeItem(instance.uid)
})
</script>
2 changes: 2 additions & 0 deletions packages/components/carousel/src/instance.ts
@@ -1,3 +1,5 @@
import type Carousel from './carousel.vue'
import type CarouselItem from './carousel-item.vue'

export type CarouselInstance = InstanceType<typeof Carousel>
export type CarouselItemInstance = InstanceType<typeof CarouselItem>
173 changes: 173 additions & 0 deletions packages/components/carousel/src/use-carousel-item.ts
@@ -0,0 +1,173 @@
import {
getCurrentInstance,
inject,
onMounted,
onUnmounted,
reactive,
ref,
unref,
} from 'vue'
import { debugWarn, isUndefined } from '@element-plus/utils'
import { carouselContextKey } from '@element-plus/tokens'

import type { CarouselItemProps } from './carousel-item'

export const useCarouselItem = (
props: CarouselItemProps,
componentName: string
) => {
const carouselContext = inject(carouselContextKey)!
// instance
const instance = getCurrentInstance()!
if (!carouselContext) {
debugWarn(
componentName,
'usage: <el-carousel></el-carousel-item></el-carousel>'
)
}

if (!instance) {
debugWarn(
componentName,
'compositional hook can only be invoked inside setups'
)
}

const CARD_SCALE = 0.83

const hover = ref(false)
const translate = ref(0)
const scale = ref(1)
const active = ref(false)
const ready = ref(false)
const inStage = ref(false)
const animating = ref(false)

// computed
const { isCardType, isVertical } = carouselContext

// methods

function processIndex(index: number, activeIndex: number, length: number) {
const lastItemIndex = length - 1
const prevItemIndex = activeIndex - 1
const nextItemIndex = activeIndex + 1
const halfItemIndex = length / 2

if (activeIndex === 0 && index === lastItemIndex) {
return -1
} else if (activeIndex === lastItemIndex && index === 0) {
return length
} else if (index < prevItemIndex && activeIndex - index >= halfItemIndex) {
return length + 1
} else if (index > nextItemIndex && index - activeIndex >= halfItemIndex) {
return -2
}
return index
}

function calcCardTranslate(index: number, activeIndex: number) {
const parentWidth = carouselContext.root.value?.offsetWidth || 0
if (inStage.value) {
return (parentWidth * ((2 - CARD_SCALE) * (index - activeIndex) + 1)) / 4
} else if (index < activeIndex) {
return (-(1 + CARD_SCALE) * parentWidth) / 4
} else {
return ((3 + CARD_SCALE) * parentWidth) / 4
}
}

function calcTranslate(
index: number,
activeIndex: number,
isVertical: boolean
) {
const rootEl = carouselContext.root.value
if (!rootEl) return 0

const distance =
(isVertical ? rootEl.offsetHeight : rootEl.offsetWidth) || 0
return distance * (index - activeIndex)
}

const translateItem = (
index: number,
activeIndex: number,
oldIndex?: number
) => {
const _isCardType = unref(isCardType)
const carouselItemLength = carouselContext.items.value.length ?? Number.NaN

const isActive = index === activeIndex
if (!_isCardType && !isUndefined(oldIndex)) {
animating.value = isActive || index === oldIndex
}

if (!isActive && carouselItemLength > 2 && carouselContext.loop) {
index = processIndex(index, activeIndex, carouselItemLength)
}

const _isVertical = unref(isVertical)
active.value = isActive

if (_isCardType) {
if (_isVertical) {
debugWarn(
'Carousel',
'vertical direction is not supported for card mode'
)
}
inStage.value = Math.round(Math.abs(index - activeIndex)) <= 1
translate.value = calcCardTranslate(index, activeIndex)
scale.value = unref(active) ? 1 : CARD_SCALE
} else {
translate.value = calcTranslate(index, activeIndex, _isVertical)
}

ready.value = true
}

function handleItemClick() {
if (carouselContext && unref(isCardType)) {
const index = carouselContext.items.value.findIndex(
({ uid }) => uid === instance.uid
)
carouselContext.setActiveItem(index)
}
}

// lifecycle
onMounted(() => {
carouselContext.addItem({
props,
states: reactive({
hover,
translate,
scale,
active,
ready,
inStage,
animating,
}),
uid: instance.uid,
translateItem,
})
})

onUnmounted(() => {
carouselContext.removeItem(instance.uid)
})

return {
active,
animating,
hover,
inStage,
isVertical,
translate,
isCardType,
scale,
ready,
handleItemClick,
}
}

0 comments on commit bfb8e26

Please sign in to comment.