fix: [디자인QA] 슬라이드 인덱스 전환 시 영상이 처음부터 재생되도록 적용
This commit is contained in:
@@ -126,7 +126,7 @@ let stopWatch: (() => void) | null = null
|
||||
onMounted(() => {
|
||||
if (!import.meta.client) return
|
||||
|
||||
useEventListener('scroll', scrollStore.updateScrollValue)
|
||||
useEventListener('scroll', scrollStore.updateScrollValue, { passive: true })
|
||||
|
||||
stopWatch = watch(
|
||||
scrollGnbPosition,
|
||||
|
||||
@@ -1,92 +1,123 @@
|
||||
<script setup lang="ts">
|
||||
import type { ClassType } from '#layers/types/Common'
|
||||
|
||||
interface Props {
|
||||
src: string
|
||||
type?: 'mp4' | 'webm'
|
||||
poster?: string
|
||||
play?: boolean
|
||||
autoplay?: boolean
|
||||
muted?: boolean
|
||||
loop?: boolean
|
||||
playsinline?: boolean
|
||||
bordered?: boolean
|
||||
class?: ClassType
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
type: 'mp4',
|
||||
play: false,
|
||||
play: true,
|
||||
muted: true,
|
||||
loop: true,
|
||||
playsinline: true,
|
||||
bordered: true,
|
||||
})
|
||||
|
||||
const videoRef = ref<HTMLVideoElement | null>(null)
|
||||
let pauseTimeoutId: ReturnType<typeof setTimeout> | null = null
|
||||
const pauseTimer = ref<ReturnType<typeof setTimeout> | null>(null)
|
||||
|
||||
// autoplay prop 변경 시 재생/정지 제어
|
||||
watch(
|
||||
() => props.play,
|
||||
shouldPlay => {
|
||||
if (!videoRef.value) return
|
||||
|
||||
// 이전 타이머 정리
|
||||
if (pauseTimeoutId) {
|
||||
clearTimeout(pauseTimeoutId)
|
||||
pauseTimeoutId = null
|
||||
}
|
||||
|
||||
if (shouldPlay) {
|
||||
videoRef.value.play().catch(err => {
|
||||
console.warn('Video play failed:', err)
|
||||
})
|
||||
} else {
|
||||
pauseTimeoutId = setTimeout(() => {
|
||||
if (videoRef.value) {
|
||||
videoRef.value.pause()
|
||||
videoRef.value.currentTime = 0
|
||||
}
|
||||
pauseTimeoutId = null
|
||||
}, 200)
|
||||
}
|
||||
const clearPauseTimer = () => {
|
||||
if (pauseTimer.value) {
|
||||
clearTimeout(pauseTimer.value)
|
||||
pauseTimer.value = null
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
// 타이머 정리
|
||||
if (pauseTimeoutId) {
|
||||
clearTimeout(pauseTimeoutId)
|
||||
pauseTimeoutId = null
|
||||
const playVideo = async () => {
|
||||
if (!videoRef.value) return
|
||||
|
||||
clearPauseTimer()
|
||||
|
||||
try {
|
||||
await videoRef.value.play()
|
||||
} catch (e) {
|
||||
console.warn('Video play failed:', e)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const pauseVideo = () => {
|
||||
if (!videoRef.value) return
|
||||
|
||||
clearPauseTimer()
|
||||
|
||||
// 새 타이머 설정
|
||||
pauseTimer.value = setTimeout(() => {
|
||||
if (videoRef.value) {
|
||||
videoRef.value.pause()
|
||||
videoRef.value.currentTime = 0
|
||||
}
|
||||
pauseTimer.value = null
|
||||
}, 500)
|
||||
}
|
||||
|
||||
const reloadVideo = async () => {
|
||||
if (!videoRef.value) return
|
||||
|
||||
clearPauseTimer()
|
||||
|
||||
videoRef.value.currentTime = 0
|
||||
videoRef.value.load()
|
||||
|
||||
if (props.play) {
|
||||
await playVideo()
|
||||
}
|
||||
}
|
||||
|
||||
const syncPlayState = (shouldPlay: boolean) => {
|
||||
if (shouldPlay) {
|
||||
void playVideo()
|
||||
} else {
|
||||
pauseVideo()
|
||||
}
|
||||
}
|
||||
|
||||
// src 변경 시 비디오 다시 로드
|
||||
watch(
|
||||
() => props.src,
|
||||
() => {
|
||||
if (!videoRef.value) return
|
||||
|
||||
// 비디오 시간 초기화 및 새 소스 로드
|
||||
videoRef.value.currentTime = 0
|
||||
videoRef.value.load()
|
||||
|
||||
// 재생 중이었다면 다시 재생
|
||||
if (props.play) {
|
||||
nextTick(() => {
|
||||
videoRef.value?.play().catch(err => {
|
||||
console.warn('Video play failed:', err)
|
||||
})
|
||||
})
|
||||
}
|
||||
void reloadVideo()
|
||||
}
|
||||
)
|
||||
|
||||
// play 상태 변경 시 재생/일시정지
|
||||
watch(
|
||||
() => props.play,
|
||||
shouldPlay => {
|
||||
syncPlayState(!!shouldPlay)
|
||||
}
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
if (props.play) {
|
||||
playVideo()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
clearPauseTimer()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="props.src" :class="['video-box', props.class]">
|
||||
<div
|
||||
v-if="props.src"
|
||||
:class="['video-box', { 'has-bordered': props.bordered }, props.class]"
|
||||
>
|
||||
<video
|
||||
ref="videoRef"
|
||||
:autoplay="props.autoplay"
|
||||
:poster="props.poster"
|
||||
:muted="props.muted"
|
||||
:loop="props.loop"
|
||||
:playsinline="props.playsinline"
|
||||
playsinline
|
||||
>
|
||||
<source :src="props.src" :type="`video/${props.type}`" />
|
||||
</video>
|
||||
@@ -95,7 +126,10 @@ watch(
|
||||
|
||||
<style scoped>
|
||||
.video-box {
|
||||
@apply overflow-hidden relative rounded-[4px] md:rounded-[8px]
|
||||
@apply overflow-hidden;
|
||||
}
|
||||
.video-box.has-bordered {
|
||||
@apply relative rounded-[4px] md:rounded-[8px]
|
||||
after:content-[''] after:absolute after:top-0 after:left-0 after:w-full after:h-full after:border after:border-white after:opacity-10 after:rounded-[4px] after:md:rounded-[8px];
|
||||
}
|
||||
.video-box video {
|
||||
|
||||
@@ -23,6 +23,8 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
|
||||
const emit = defineEmits(['mounted', 'move', 'arrowClick'])
|
||||
|
||||
const splideIndex = defineModel<number>('index', { required: false })
|
||||
|
||||
// Splide 화살표 로직을 위한 composable 사용
|
||||
const { addArrowClickListeners } = useSplideArrow()
|
||||
|
||||
@@ -90,6 +92,10 @@ const handleSplideMounted = (splide: SplideType) => {
|
||||
emit('mounted', splide)
|
||||
splide.refresh()
|
||||
|
||||
if (splideIndex.value !== undefined) {
|
||||
splideIndex.value = splide.index
|
||||
}
|
||||
|
||||
// 화살표 버튼 클릭 이벤트 리스너 추가
|
||||
nextTick(() => {
|
||||
addArrowClickListeners(splide, (direction, targetIndex) => {
|
||||
@@ -105,6 +111,10 @@ const handleMove = (
|
||||
destIndex: number
|
||||
) => {
|
||||
emit('move', splide, newIndex, oldIndex, destIndex)
|
||||
|
||||
if (splideIndex.value !== undefined) {
|
||||
splideIndex.value = newIndex
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -22,6 +22,8 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
|
||||
const emit = defineEmits(['mounted', 'move', 'arrowClick'])
|
||||
|
||||
const splideIndex = defineModel<number>('index', { required: false })
|
||||
|
||||
// Splide 화살표 로직을 위한 composable 사용
|
||||
const { addArrowClickListeners } = useSplideArrow()
|
||||
|
||||
@@ -92,6 +94,10 @@ const handleSplideMounted = (splide: SplideType) => {
|
||||
emit('mounted', splide)
|
||||
splide.refresh()
|
||||
|
||||
if (splideIndex.value !== undefined) {
|
||||
splideIndex.value = splide.index
|
||||
}
|
||||
|
||||
// 화살표 버튼 클릭 이벤트 리스너 추가
|
||||
nextTick(() => {
|
||||
addArrowClickListeners(splide, (direction, targetIndex) => {
|
||||
@@ -107,6 +113,10 @@ const handleMove = (
|
||||
destIndex: number
|
||||
) => {
|
||||
emit('move', splide, newIndex, oldIndex, destIndex)
|
||||
|
||||
if (splideIndex.value !== undefined) {
|
||||
splideIndex.value = newIndex
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -31,6 +31,8 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
|
||||
const emit = defineEmits(['mounted', 'move', 'arrowClick'])
|
||||
|
||||
const splideIndex = defineModel<number>('index', { required: false })
|
||||
|
||||
// Splide 화살표 로직을 위한 composable 사용
|
||||
const { addArrowClickListeners } = useSplideArrow()
|
||||
|
||||
@@ -72,6 +74,10 @@ const options = computed((): ResponsiveOptions => {
|
||||
const handleSplideMounted = (splide: SplideType) => {
|
||||
emit('mounted', splide)
|
||||
|
||||
if (splideIndex.value !== undefined) {
|
||||
splideIndex.value = splide.index
|
||||
}
|
||||
|
||||
// 화살표 버튼 클릭 이벤트 리스너 추가
|
||||
nextTick(() => {
|
||||
addArrowClickListeners(splide, (direction, targetIndex) => {
|
||||
@@ -87,6 +93,10 @@ const handleMove = (
|
||||
destIndex: number
|
||||
) => {
|
||||
emit('move', splide, newIndex, oldIndex, destIndex)
|
||||
|
||||
if (splideIndex.value !== undefined) {
|
||||
splideIndex.value = newIndex
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -24,6 +24,8 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
|
||||
const emit = defineEmits(['mounted', 'move', 'arrowClick'])
|
||||
|
||||
const splideIndex = defineModel<number>('index', { required: false })
|
||||
|
||||
const splideRef = ref()
|
||||
// Splide 화살표 로직을 위한 composable 사용
|
||||
const { addArrowClickListeners } = useSplideArrow()
|
||||
@@ -56,13 +58,13 @@ const options = computed((): ResponsiveOptions => {
|
||||
}
|
||||
})
|
||||
|
||||
defineExpose({
|
||||
splide: computed(() => splideRef.value?.splide),
|
||||
})
|
||||
|
||||
const handleSplideMounted = (splide: SplideType) => {
|
||||
emit('mounted', splide)
|
||||
|
||||
if (splideIndex.value !== undefined) {
|
||||
splideIndex.value = splide.index
|
||||
}
|
||||
|
||||
// 화살표 버튼 클릭 이벤트 리스너 추가
|
||||
nextTick(() => {
|
||||
addArrowClickListeners(splide, (direction, targetIndex) => {
|
||||
@@ -78,7 +80,15 @@ const handleMove = (
|
||||
destIndex: number
|
||||
) => {
|
||||
emit('move', splide, newIndex, oldIndex, destIndex)
|
||||
|
||||
if (splideIndex.value !== undefined) {
|
||||
splideIndex.value = newIndex
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
splide: computed(() => splideRef.value?.splide),
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -21,6 +21,8 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
|
||||
const emit = defineEmits(['mounted', 'move', 'arrowClick'])
|
||||
|
||||
const splideIndex = defineModel<number>('index', { required: false })
|
||||
|
||||
// Splide 화살표 로직을 위한 composable 사용
|
||||
const { addArrowClickListeners } = useSplideArrow()
|
||||
|
||||
@@ -88,6 +90,14 @@ const getThumbnailSrc = (item: PageDataResourceGroup) => {
|
||||
return getResourceSrc(item)
|
||||
}
|
||||
|
||||
const handleSplideMounted = (splide: SplideType) => {
|
||||
emit('mounted', splide)
|
||||
|
||||
if (splideIndex.value !== undefined) {
|
||||
splideIndex.value = splide.index
|
||||
}
|
||||
}
|
||||
|
||||
const handleMove = (
|
||||
splide: SplideType,
|
||||
newIndex: number,
|
||||
@@ -95,10 +105,10 @@ const handleMove = (
|
||||
destIndex: number
|
||||
) => {
|
||||
emit('move', splide, newIndex, oldIndex, destIndex)
|
||||
}
|
||||
|
||||
const handleSplideMounted = (splide: SplideType) => {
|
||||
emit('mounted', splide)
|
||||
if (splideIndex.value !== undefined) {
|
||||
splideIndex.value = newIndex
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
@@ -141,8 +151,8 @@ onBeforeUnmount(() => {
|
||||
ref="mainRef"
|
||||
:options="mainOptions"
|
||||
class="main-splide"
|
||||
@splide:move="handleMove"
|
||||
@splide:mounted="handleSplideMounted"
|
||||
@splide:move="handleMove"
|
||||
>
|
||||
<slot />
|
||||
</Splide>
|
||||
|
||||
@@ -4,20 +4,20 @@ import type { PageDataResourceGroup } from '#layers/types/api/pageData'
|
||||
interface Props {
|
||||
resourcesData: PageDataResourceGroup
|
||||
size?: 'contain' | 'cover'
|
||||
videoPlay?: boolean
|
||||
gradient?: string
|
||||
dimmed?: boolean
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
size: 'cover',
|
||||
videoPlay: true,
|
||||
gradient: '',
|
||||
dimmed: false,
|
||||
})
|
||||
|
||||
const { getCurrentSrc } = useResponsiveSrc()
|
||||
|
||||
const videoRef = ref<HTMLVideoElement | null>(null)
|
||||
|
||||
const resourcesSrc = computed(() => {
|
||||
return getCurrentSrc(props.resourcesData)
|
||||
})
|
||||
@@ -32,28 +32,6 @@ const gradientClasses = computed(() => [
|
||||
'absolute bottom-[-2px] left-[-2px] right-[-2px]',
|
||||
props.gradient,
|
||||
])
|
||||
|
||||
// 비디오를 처음부터 재생하는 메서드
|
||||
const restartVideo = () => {
|
||||
if (!videoRef.value) return
|
||||
|
||||
videoRef.value.currentTime = 0
|
||||
videoRef.value.play().catch(err => {
|
||||
console.warn('Video play failed:', err)
|
||||
})
|
||||
}
|
||||
|
||||
// src 변경 시 비디오 다시 로드
|
||||
watch(resourcesSrc, () => {
|
||||
if (!videoRef.value) return
|
||||
|
||||
videoRef.value.currentTime = 0
|
||||
videoRef.value.load()
|
||||
})
|
||||
|
||||
defineExpose({
|
||||
restartVideo,
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -69,18 +47,13 @@ defineExpose({
|
||||
/>
|
||||
|
||||
<!-- 비디오 타입 -->
|
||||
<video
|
||||
<AtomsVideo
|
||||
v-else-if="isTypeVideo(resourcesData?.resource_type)"
|
||||
ref="videoRef"
|
||||
class="w-full h-full object-cover"
|
||||
:src="resourcesSrc"
|
||||
:poster="posterSrc"
|
||||
autoplay
|
||||
muted
|
||||
loop
|
||||
playsinline
|
||||
>
|
||||
<source :src="resourcesSrc" type="video/mp4" />
|
||||
</video>
|
||||
:play="videoPlay"
|
||||
class="w-full h-full object-cover"
|
||||
/>
|
||||
|
||||
<i v-if="dimmed" class="absolute inset-0 bg-black/50" />
|
||||
<i v-if="gradient" :class="gradientClasses" />
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { GameDataRequest, GameDataValue } from '#layers/types/api/gameData'
|
||||
import type { GameDataValue } from '#layers/types/api/gameData'
|
||||
|
||||
export default defineNuxtRouteMiddleware(async (to, _from) => {
|
||||
const nuxtApp = useNuxtApp()
|
||||
@@ -59,12 +59,11 @@ export default defineNuxtRouteMiddleware(async (to, _from) => {
|
||||
to.path.includes('/error') ||
|
||||
to.path.includes('/inspection')
|
||||
) {
|
||||
console.log("🚀 ~ init.route.global error 페이지는 API 호출하지 않음")
|
||||
console.log('🚀 ~ init.route.global error 페이지는 API 호출하지 않음')
|
||||
showError(
|
||||
createError({
|
||||
statusCode: 500,
|
||||
statusMessage:
|
||||
'Internal Server Error',
|
||||
statusMessage: 'Internal Server Error',
|
||||
fatal: false, // 즉시 에러 페이지로
|
||||
data: { reason: 'post-not-found' },
|
||||
})
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
getComponentContainer,
|
||||
} from '#layers/utils/dataUtil'
|
||||
import { getYouTubeThumbnail } from '#layers/utils/youtubeUtil'
|
||||
import type { Splide as SplideType } from '@splidejs/splide'
|
||||
import type { PageDataTemplateComponents } from '#layers/types/api/pageData'
|
||||
import type { OperateGroupItem } from '#layers/types/api/operateResources'
|
||||
|
||||
@@ -84,7 +83,8 @@ const ITEMS_PER_PAGE = {
|
||||
MOBILE: 8,
|
||||
DESKTOP: 12,
|
||||
} as const
|
||||
const currentRecommendedIndex = ref(1)
|
||||
|
||||
const currentRecommendedIndex = ref<number | null>(null)
|
||||
const currentRecentPage = ref(1)
|
||||
|
||||
// 추천 영상 (option01 === 1)
|
||||
@@ -110,10 +110,6 @@ const hasMore = computed(
|
||||
() => visibleVideos.value.length < recentVideos.value.length
|
||||
)
|
||||
|
||||
const handleSplideMove = (_splide: SplideType, newIndex: number) => {
|
||||
currentRecommendedIndex.value = newIndex + 1
|
||||
}
|
||||
|
||||
const handleVideoClick = (url: string) => {
|
||||
modalStore.handleOpenYoutube({ youtubeUrl: url })
|
||||
}
|
||||
@@ -142,12 +138,12 @@ const handleLoadMoreRecent = () => {
|
||||
class="relative content-static bg-[#fff] rounded-[12px] md:rounded-[16px]"
|
||||
>
|
||||
<BlocksSlideFade
|
||||
v-model:index="currentRecommendedIndex"
|
||||
:autoplay="recommendedVideos.length > 1"
|
||||
:interval="3000"
|
||||
:arrows="recommendedVideos.length > 1"
|
||||
:pagination="false"
|
||||
:drag="false"
|
||||
@move="handleSplideMove"
|
||||
>
|
||||
<SplideSlide
|
||||
v-for="(item, index) in recommendedVideos"
|
||||
@@ -192,7 +188,7 @@ const handleLoadMoreRecent = () => {
|
||||
</BlocksSlideFade>
|
||||
<div v-if="recommendedVideos.length > 1" class="splide-pagination">
|
||||
<span class="font-[700] text-[#1F1F1F]">
|
||||
{{ currentRecommendedIndex }}
|
||||
{{ currentRecommendedIndex + 1 }}
|
||||
</span>
|
||||
/
|
||||
<span>{{ recommendedVideos.length }}</span>
|
||||
|
||||
@@ -4,7 +4,6 @@ import {
|
||||
getComponentContainer,
|
||||
getComponentGroupAry,
|
||||
} from '#layers/utils/dataUtil'
|
||||
import type { Splide as SplideType } from '@splidejs/splide'
|
||||
import type { PageDataTemplateComponents } from '#layers/types/api/pageData'
|
||||
|
||||
interface Props {
|
||||
@@ -30,14 +29,6 @@ const goToSlide = (index: number) => {
|
||||
splide.go(index)
|
||||
}
|
||||
}
|
||||
|
||||
const handleSplideMounted = (splide: SplideType) => {
|
||||
currentSlideIndex.value = splide.index
|
||||
}
|
||||
|
||||
const handleSplideMove = (_splide: SplideType, newIndex: number) => {
|
||||
currentSlideIndex.value = newIndex
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -45,17 +36,17 @@ const handleSplideMove = (_splide: SplideType, newIndex: number) => {
|
||||
<BlocksSlideFade
|
||||
v-if="slideData"
|
||||
ref="splideRef"
|
||||
v-model:index="currentSlideIndex"
|
||||
:autoplay="true"
|
||||
:arrows="false"
|
||||
:pagination="false"
|
||||
class="h-full"
|
||||
@move="handleSplideMove"
|
||||
@mounted="handleSplideMounted"
|
||||
>
|
||||
<SplideSlide v-for="(item, index) in slideData" :key="index">
|
||||
<WidgetsBackground
|
||||
v-if="hasComponentGroup(item, 'background')"
|
||||
:resources-data="getComponentGroup(item, 'background')"
|
||||
:video-play="currentSlideIndex === index"
|
||||
/>
|
||||
<div class="content-standard">
|
||||
<WidgetsMainTitle
|
||||
|
||||
@@ -13,6 +13,8 @@ interface Props {
|
||||
|
||||
const props = defineProps<Props>()
|
||||
|
||||
const currentSlideIndex = ref<number | null>(null)
|
||||
|
||||
const slideData = computed(() => {
|
||||
return getComponentContainer(props.components, 'group_sets', { maxLength: 7 })
|
||||
})
|
||||
@@ -29,6 +31,7 @@ const paginationData = computed(() => {
|
||||
<template>
|
||||
<section class="section-standard">
|
||||
<BlocksSlideThumbnail
|
||||
v-model:index="currentSlideIndex"
|
||||
:thumbnail-data="thumbnailData"
|
||||
:pagination-data="paginationData"
|
||||
>
|
||||
@@ -36,6 +39,7 @@ const paginationData = computed(() => {
|
||||
<WidgetsBackground
|
||||
v-if="hasComponentGroup(item, 'background')"
|
||||
:resources-data="getComponentGroup(item, 'background')"
|
||||
:video-play="currentSlideIndex === index"
|
||||
/>
|
||||
<div class="content-standard">
|
||||
<WidgetsMainTitle
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
getComponentGroup,
|
||||
hasComponentGroup,
|
||||
} from '#layers/utils/dataUtil'
|
||||
import type { Splide as SplideType } from '@splidejs/splide'
|
||||
import type {
|
||||
PageDataTemplateComponents,
|
||||
PageDataTemplateComponent,
|
||||
@@ -21,7 +20,7 @@ const props = defineProps<Props>()
|
||||
|
||||
const { getCurrentSrc } = useResponsiveSrc()
|
||||
|
||||
const currentSlideIndex = ref<number>(0)
|
||||
const currentSlideIndex = ref<number | null>(null)
|
||||
|
||||
const slideData = computed(() => {
|
||||
return getComponentContainer(props.components, 'group_sets', {
|
||||
@@ -37,27 +36,24 @@ const paginationData = computed(() => {
|
||||
return getComponentGroupAry(props.components, 'pagination')
|
||||
})
|
||||
|
||||
const videoSrc = (item: PageDataTemplateComponent) => {
|
||||
const getVideoSrc = (item: PageDataTemplateComponent) => {
|
||||
const videoData = getComponentGroup(item, 'video')
|
||||
return getCurrentSrc(videoData)
|
||||
}
|
||||
|
||||
const handleSplideMove = (_splide: SplideType, newIndex: number) => {
|
||||
currentSlideIndex.value = newIndex
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="section-standard">
|
||||
<BlocksSlideThumbnail
|
||||
v-model:index="currentSlideIndex"
|
||||
:thumbnail-data="thumbnailData"
|
||||
:pagination-data="paginationData"
|
||||
@move="handleSplideMove"
|
||||
>
|
||||
<SplideSlide v-for="(item, index) in slideData" :key="index">
|
||||
<WidgetsBackground
|
||||
v-if="hasComponentGroup(item, 'background')"
|
||||
:resources-data="getComponentGroup(item, 'background')"
|
||||
:video-play="currentSlideIndex === index"
|
||||
/>
|
||||
<WidgetsBackground
|
||||
v-if="hasComponentGroup(item, 'foreground')"
|
||||
@@ -89,12 +85,8 @@ const handleSplideMove = (_splide: SplideType, newIndex: number) => {
|
||||
/>
|
||||
<AtomsVideo
|
||||
v-if="hasComponentGroup(item, 'video')"
|
||||
:src="videoSrc(item)"
|
||||
:src="getVideoSrc(item)"
|
||||
:play="currentSlideIndex === index"
|
||||
autoplay
|
||||
muted
|
||||
loop
|
||||
playsinline
|
||||
class="aspect-[16/10] w-[258px] mt-8 md:w-[496px] md:mt-10"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -19,7 +19,6 @@ const props = defineProps<Props>()
|
||||
const { locale } = useI18n()
|
||||
const { sendLog, useAnalyticsLogDataDirect } = useAnalytics()
|
||||
|
||||
const slideThumbnailRef = ref<any>(null)
|
||||
const playingSlideIndex = ref<number | null>(null)
|
||||
let stopVideoTimeoutId: ReturnType<typeof setTimeout> | null = null
|
||||
|
||||
@@ -65,7 +64,7 @@ const handleVideoClick = (index: number) => {
|
||||
)
|
||||
}
|
||||
|
||||
const stopVideo = () => {
|
||||
const handleSplideMove = () => {
|
||||
// 이전 타이머 정리
|
||||
if (stopVideoTimeoutId) {
|
||||
clearTimeout(stopVideoTimeoutId)
|
||||
@@ -104,14 +103,13 @@ onBeforeUnmount(() => {
|
||||
class="title-md max-w-[944px]"
|
||||
/>
|
||||
<BlocksSlideThumbnail
|
||||
ref="slideThumbnailRef"
|
||||
:thumbnail-data="slideData"
|
||||
variant="media"
|
||||
class="mt-[24px] md:mt-[32px]"
|
||||
:pagination-data="paginationData"
|
||||
:arrows="slideData.length > 5"
|
||||
@move="stopVideo"
|
||||
@arrow-click="onArrowClick"
|
||||
@move="handleSplideMove"
|
||||
>
|
||||
<SplideSlide
|
||||
v-for="(item, index) in slideData"
|
||||
|
||||
@@ -18,6 +18,8 @@ const props = defineProps<Props>()
|
||||
const { locale } = useI18n()
|
||||
const { sendLog, useAnalyticsLogDataDirect } = useAnalytics()
|
||||
|
||||
const currentSlideIndex = ref<number | null>(null)
|
||||
|
||||
const slideData = computed(() => {
|
||||
return getComponentContainer(props.components, 'group_sets')
|
||||
})
|
||||
@@ -36,6 +38,7 @@ const onArrowClick = direction => {
|
||||
<section class="section-standard">
|
||||
<BlocksSlideFade
|
||||
v-if="slideData"
|
||||
v-model:index="currentSlideIndex"
|
||||
:arrows="slideData.length > 1"
|
||||
:pagination="slideData.length > 1"
|
||||
class="h-full"
|
||||
@@ -46,6 +49,7 @@ const onArrowClick = direction => {
|
||||
<WidgetsBackground
|
||||
v-if="hasComponentGroup(item, 'background')"
|
||||
:resources-data="getComponentGroup(item, 'background')"
|
||||
:video-play="currentSlideIndex === index"
|
||||
/>
|
||||
<div class="content-standard gap-3 md:gap-5">
|
||||
<WidgetsSubTitle
|
||||
|
||||
Reference in New Issue
Block a user