feat: 슬라이드 화살표 클릭 로그 추가 및 관련 로직 개선

This commit is contained in:
“hyeonggkim”
2025-10-20 20:08:10 +09:00
parent 9f6056ef77
commit a36489c264
9 changed files with 139 additions and 91 deletions

View File

@@ -10,12 +10,28 @@ interface Props {
}
const props = defineProps<Props>()
const {locale} = useI18n()
const { sendLog, useAnalyticsLogDataDirect } = useAnalytics()
const handleLinkClick = (title) => {
const trackingData = {
tracking: {
click_item: title,
action_type: 'click',
click_sarea: ''
}
}
sendLog(locale.value, useAnalyticsLogDataDirect(trackingData, 1))
}
</script>
<template>
<div
v-if="props.title || props.description"
:class="`card-news ${props.class || ''}`"
@click="handleLinkClick(props.title)"
>
<img
:src="props.imgPath"

View File

@@ -2,6 +2,7 @@
import { Splide } from '@splidejs/vue-splide'
import type { Splide as SplideType, ResponsiveOptions } from '@splidejs/splide'
import type { SlideItemSize } from '#layers/types/components/slide'
import { useSplideArrow } from '#layers/composables/useSplideArrow'
interface Props {
slideItemSize: SlideItemSize
@@ -20,6 +21,9 @@ const props = withDefaults(defineProps<Props>(), {
const emit = defineEmits(['mounted', 'move', 'moved', 'arrowClick'])
// Splide 화살표 로직을 위한 composable 사용
const { addArrowClickListeners } = useSplideArrow()
const isMultipleItems = computed(() => {
return props.slideItemLength > 1
})
@@ -85,7 +89,9 @@ const handleSplideMounted = (splide: SplideType) => {
// 화살표 버튼 클릭 이벤트 리스너 추가
nextTick(() => {
addArrowClickListeners(splide)
addArrowClickListeners(splide, (direction, targetIndex) => {
emit('arrowClick', direction, targetIndex)
})
})
}
@@ -107,34 +113,6 @@ const handleMoved = (
emit('moved', splide, newIndex, oldIndex, destIndex)
}
const handleArrowClick = (direction: 'prev' | 'next', splide: SplideType) => {
const currentIndex = splide.index
const totalSlides = splide.length
// 이동할 슬라이드 인덱스 계산
let targetIndex: number
if (direction === 'next') {
targetIndex = currentIndex + 1 >= totalSlides ? 0 : currentIndex + 1
} else {
targetIndex = currentIndex - 1 < 0 ? totalSlides - 1 : currentIndex - 1
}
emit('arrowClick', direction, targetIndex)
}
// 화살표 버튼에 클릭 이벤트 리스너 추가
const addArrowClickListeners = (splide: SplideType) => {
const prevArrow = splide.root.querySelector('.arrow-prev')
const nextArrow = splide.root.querySelector('.arrow-next')
if (prevArrow) {
prevArrow.addEventListener('click', () => handleArrowClick('prev', splide))
}
if (nextArrow) {
nextArrow.addEventListener('click', () => handleArrowClick('next', splide))
}
}
</script>

View File

@@ -18,7 +18,10 @@ const props = withDefaults(defineProps<Props>(), {
pagination: true,
})
const emit = defineEmits(['mounted', 'move', 'moved'])
const emit = defineEmits(['mounted', 'move', 'moved', 'arrowClick'])
// Splide 화살표 로직을 위한 composable 사용
const { addArrowClickListeners } = useSplideArrow()
const isMultipleItems = computed(() => {
return props.slideItemLength > 1
@@ -85,6 +88,13 @@ const style = computed(() => {
const handleSplideMounted = (splide: SplideType) => {
emit('mounted', splide)
splide.refresh()
// 화살표 버튼 클릭 이벤트 리스너 추가
nextTick(() => {
addArrowClickListeners(splide, (direction, targetIndex) => {
emit('arrowClick', direction, targetIndex)
})
})
}
const handleMove = (

View File

@@ -1,6 +1,7 @@
<script setup lang="ts">
import { Splide } from '@splidejs/vue-splide'
import type { Splide as SplideType, ResponsiveOptions } from '@splidejs/splide'
import { useSplideArrow } from '#layers/composables/useSplideArrow'
interface Props {
autoplay?: boolean | string
@@ -18,6 +19,9 @@ const props = withDefaults(defineProps<Props>(), {
const emit = defineEmits(['mounted', 'move', 'moved', 'arrowClick'])
// Splide 화살표 로직을 위한 composable 사용
const { addArrowClickListeners } = useSplideArrow()
const options = computed((): ResponsiveOptions => {
return {
type: 'fade',
@@ -47,7 +51,9 @@ const handleSplideMounted = (splide: SplideType) => {
// 화살표 버튼 클릭 이벤트 리스너 추가
nextTick(() => {
addArrowClickListeners(splide)
addArrowClickListeners(splide, (direction, targetIndex) => {
emit('arrowClick', direction, targetIndex)
})
})
}
@@ -69,34 +75,6 @@ const handleMoved = (
emit('moved', splide, newIndex, oldIndex, destIndex)
}
const handleArrowClick = (direction: 'prev' | 'next', splide: SplideType) => {
const currentIndex = splide.index
const totalSlides = splide.length
// 이동할 슬라이드 인덱스 계산
let targetIndex: number
if (direction === 'next') {
targetIndex = currentIndex + 1 >= totalSlides ? 0 : currentIndex + 1
} else {
targetIndex = currentIndex - 1 < 0 ? totalSlides - 1 : currentIndex - 1
}
emit('arrowClick', direction, targetIndex)
}
// 화살표 버튼에 클릭 이벤트 리스너 추가
const addArrowClickListeners = (splide: SplideType) => {
const prevArrow = splide.root.querySelector('.arrow-prev')
const nextArrow = splide.root.querySelector('.arrow-next')
if (prevArrow) {
prevArrow.addEventListener('click', () => handleArrowClick('prev', splide))
}
if (nextArrow) {
nextArrow.addEventListener('click', () => handleArrowClick('next', splide))
}
}
</script>
<template>

View File

@@ -11,6 +11,7 @@ import type {
PageDataTemplateComponentSet,
PageDataResourceGroup,
} from '#layers/types/api/pageData'
import { useSplideArrow } from '#layers/composables/useSplideArrow'
interface Props {
slideData: PageDataTemplateComponentSet[]
@@ -27,6 +28,9 @@ const { sendLog, useAnalyticsLogDataDirect } = useAnalytics()
const emit = defineEmits(['arrowClick'])
// Splide 화살표 로직을 위한 composable 사용
const { addArrowClickListeners } = useSplideArrow()
let mainInst: SplideType | null = null
let thumbsInst: SplideType | null = null
@@ -107,34 +111,6 @@ const stopVideo = () => {
playingSlideIndex.value = null
}
const handleArrowClick = (direction: 'prev' | 'next', splide: SplideType) => {
const currentIndex = splide.index
const totalSlides = splide.length
// 이동할 슬라이드 인덱스 계산
let targetIndex: number
if (direction === 'next') {
targetIndex = currentIndex + 1 >= totalSlides ? 0 : currentIndex + 1
} else {
targetIndex = currentIndex - 1 < 0 ? totalSlides - 1 : currentIndex - 1
}
emit('arrowClick', direction, targetIndex)
}
// 화살표 버튼에 클릭 이벤트 리스너 추가
const addArrowClickListeners = (splide: SplideType) => {
const prevArrow = splide.root.querySelector('.arrow-prev')
const nextArrow = splide.root.querySelector('.arrow-next')
if (prevArrow) {
prevArrow.addEventListener('click', () => handleArrowClick('prev', splide))
}
if (nextArrow) {
nextArrow.addEventListener('click', () => handleArrowClick('next', splide))
}
}
onMounted(() => {
mainInst = mainRef.value?.splide ?? null
@@ -146,7 +122,9 @@ onMounted(() => {
// 썸네일 슬라이드의 화살표 버튼에 이벤트 리스너 추가
nextTick(() => {
addArrowClickListeners(thumbsInst)
addArrowClickListeners(thumbsInst, (direction, targetIndex) => {
emit('arrowClick', direction, targetIndex)
})
})
}
})

View File

@@ -5,22 +5,25 @@ const props = defineProps<{
resourcesData: PageDataResourceGroup
pageVerTmplSeq: number
}>()
const { useAnalyticsLogDataDirect } = useAnalytics()
const logData = useAnalyticsLogDataDirect(props.resourcesData, props.pageVerTmplSeq)
// YouTube 모달 스토어 사용
const modalStore = useModalStore()
const {locale} = useI18n()
const { sendLog, useAnalyticsLogDataDirect } = useAnalytics()
// 비디오 플레이 버튼 클릭 핸들러
const handleVideoPlayClick = () => {
const youtubeUrl = props.resourcesData?.display?.text ?? ''
modalStore.handleOpenYoutube({ youtubeUrl })
sendLog(locale.value, useAnalyticsLogDataDirect(props.resourcesData, props.pageVerTmplSeq))
}
</script>
<template>
<AtomsButtonPlay
v-analytics="logData"
:resources-data="resourcesData"
@click="handleVideoPlayClick"
/>

View File

@@ -0,0 +1,68 @@
import type { Splide as SplideType } from '@splidejs/splide'
/**
* Splide 슬라이더의 화살표 클릭 로직을 처리하는 composable
*/
export const useSplideArrow = () => {
/**
* 화살표 클릭 시 슬라이드 인덱스를 계산하는 함수
* @param direction - 이동 방향 ('prev' | 'next')
* @param splide - Splide 인스턴스
* @returns 다음 슬라이드 인덱스
*/
const calculateTargetIndex = (direction: 'prev' | 'next', splide: SplideType): number => {
const currentIndex = splide.index
const totalSlides = splide.length
if (direction === 'next') {
return currentIndex + 1 >= totalSlides ? 0 : currentIndex + 1
} else {
return currentIndex - 1 < 0 ? totalSlides - 1 : currentIndex - 1
}
}
/**
* 화살표 클릭 핸들러
* @param direction - 이동 방향
* @param splide - Splide 인스턴스
* @param onArrowClick - 화살표 클릭 시 실행될 콜백 함수
*/
const handleArrowClick = (
direction: 'prev' | 'next',
splide: SplideType,
onArrowClick?: (direction: 'prev' | 'next', targetIndex: number) => void
) => {
const targetIndex = calculateTargetIndex(direction, splide)
if (onArrowClick) {
onArrowClick(direction, targetIndex)
}
}
/**
* 화살표 버튼에 클릭 이벤트 리스너를 추가하는 함수
* @param splide - Splide 인스턴스
* @param onArrowClick - 화살표 클릭 시 실행될 콜백 함수
*/
const addArrowClickListeners = (
splide: SplideType,
onArrowClick?: (direction: 'prev' | 'next', targetIndex: number) => void
) => {
const prevArrow = splide.root.querySelector('.arrow-prev')
const nextArrow = splide.root.querySelector('.arrow-next')
if (prevArrow) {
prevArrow.addEventListener('click', () => handleArrowClick('prev', splide, onArrowClick))
}
if (nextArrow) {
nextArrow.addEventListener('click', () => handleArrowClick('next', splide, onArrowClick))
}
}
return {
calculateTargetIndex,
handleArrowClick,
addArrowClickListeners
}
}

View File

@@ -60,6 +60,12 @@ const handleChange = (
'buttonList'
)
}
const {locale} = useI18n()
const { sendLog, useAnalyticsLogDataDirect } = useAnalytics()
const onArrowClick = (direction, targetIndex) => {
const logTraking = direction == 'prev' ? props.components.arrow.groups[0] : props.components.arrow.groups[1];
sendLog(locale.value, useAnalyticsLogDataDirect(logTraking, 1))
}
</script>
<template>
@@ -78,6 +84,7 @@ const handleChange = (
:pagination="false"
class="mt-[24px] md:mt-[48px]"
@move="handleChange"
@arrow-click="onArrowClick"
>
<SplideSlide v-for="(item, index) in slideData" :key="index">
<div class="slide-inner border-line">

View File

@@ -71,6 +71,14 @@ const slideItemSize = {
gap: 32,
},
}
const {locale} = useI18n()
const { sendLog, useAnalyticsLogDataDirect } = useAnalytics()
const onArrowClick = (direction, targetIndex) => {
const logTraking = direction == 'prev' ? props.components.arrow.groups[0] : props.components.arrow.groups[1];
sendLog(locale.value, useAnalyticsLogDataDirect(logTraking, 1))
}
console.log('resourcesData.value===', resourcesData.value)
</script>
<template>
@@ -96,6 +104,7 @@ const slideItemSize = {
:resources-data="videoPlayData"
:page-ver-tmpl-seq="Number(props.pageVerTmplSeq)"
/>
<WidgetsButtonList
v-if="buttonListData.length > 0"
:resources-data="buttonListData"
@@ -108,6 +117,7 @@ const slideItemSize = {
:slide-item-length="slideData?.length"
:pagination="false"
class="mt-[36px] md:mt-[60px]"
@arrow-click="onArrowClick"
>
<SplideSlide v-for="(item, index) in slideData" :key="index">
<BlocksCardNews