Vue.js Media Transformer - Všechny varianty implementace
1. Composable (Vue 3 Composition API)
// composables/useMediaObjects.js
export function useMediaObjects ( ) {
const transformMediaObjects = ( productGallery , productVideos ) => {
const finalObjects = [ ]
// Photos
if ( productGallery ) {
finalObjects . push (
...productGallery . map ( ( photo , index ) => ( {
...photo ,
type : 'photo' ,
rank : index + 1
} ) )
)
}
// Videos
if ( productVideos ) {
finalObjects . push (
...productVideos . map ( ( videoUrl , index ) => {
const youtubeId = extractYouTubeId ( videoUrl )
return {
url : videoUrl ,
type : 'video' ,
rank : finalObjects . length + index + 1 ,
previewThumb : youtubeId
? `https://img.youtube.com/vi/${ youtubeId } /sddefault.jpg`
: null
}
} )
)
}
return finalObjects
}
const extractYouTubeId = ( url ) => {
return url . match (
/ (?: y o u t u b e \. c o m \/ (?: [ ^ \/ ] + \/ .+ \/ | (?: v | e (?: m b e d ) ? ) \/ | .* [ ? & ] v = ) | y o u t u \. b e \/ ) ( [ ^ " & ? \/ \s ] { 11 } ) /
) ?. [ 1 ]
}
return {
transformMediaObjects,
extractYouTubeId
}
}
// Product.vue
< script setup >
import { computed } from 'vue'
import { useMediaObjects } from '@/composables/useMediaObjects'
const props = defineProps(['productGallery', 'product'])
const { transformMediaObjects } = useMediaObjects()
const mediaObjects = computed(() => {
return transformMediaObjects ( props . productGallery , props . product ?. product_video )
} )
</ script >
2. JS Třída - Statické metody
// services/MediaTransformer.js
export class MediaTransformer {
static transform ( productGallery , productVideos ) {
const finalObjects = [ ]
if ( productGallery ) {
finalObjects . push (
...productGallery . map ( ( photo , index ) => ( {
...photo ,
type : 'photo' ,
rank : index + 1
} ) )
)
}
if ( productVideos ) {
finalObjects . push (
...productVideos . map ( ( videoUrl , index ) => {
const youtubeId = this . extractYouTubeId ( videoUrl )
return {
url : videoUrl ,
type : 'video' ,
rank : finalObjects . length + index + 1 ,
previewThumb : youtubeId
? `https://img.youtube.com/vi/${ youtubeId } /sddefault.jpg`
: null
}
} )
)
}
return finalObjects
}
static extractYouTubeId ( url ) {
return url . match (
/ (?: y o u t u b e \. c o m \/ (?: [ ^ \/ ] + \/ .+ \/ | (?: v | e (?: m b e d ) ? ) \/ | .* [ ? & ] v = ) | y o u t u \. b e \/ ) ( [ ^ " & ? \/ \s ] { 11 } ) /
) ?. [ 1 ]
}
static generateThumbnail ( youtubeId , quality = 'sddefault' ) {
return `https://img.youtube.com/vi/${ youtubeId } /${ quality } .jpg`
}
}
// Product.vue
< script setup >
import { computed } from 'vue'
import { MediaTransformer } from '@/services/MediaTransformer'
const props = defineProps(['productGallery', 'product'])
const mediaObjects = computed(() => {
return MediaTransformer . transform ( props . productGallery , props . product ?. product_video )
} )
</ script >
3. JS Třída - Export třídy (instance v komponentě)
// services/MediaTransformer.js
export class MediaTransformer {
constructor ( config = { } ) {
this . thumbnailQuality = config . thumbnailQuality || 'sddefault'
this . defaultVideoType = config . defaultVideoType || 'video'
}
transform ( productGallery , productVideos ) {
const finalObjects = [ ]
if ( productGallery ) {
finalObjects . push (
...productGallery . map ( ( photo , index ) => ( {
...photo ,
type : 'photo' ,
rank : index + 1
} ) )
)
}
if ( productVideos ) {
finalObjects . push (
...productVideos . map ( ( videoUrl , index ) => {
const youtubeId = this . extractYouTubeId ( videoUrl )
return {
url : videoUrl ,
type : this . defaultVideoType ,
rank : finalObjects . length + index + 1 ,
previewThumb : youtubeId
? `https://img.youtube.com/vi/${ youtubeId } /${ this . thumbnailQuality } .jpg`
: null
}
} )
)
}
return finalObjects
}
extractYouTubeId ( url ) {
return url . match (
/ (?: y o u t u b e \. c o m \/ (?: [ ^ \/ ] + \/ .+ \/ | (?: v | e (?: m b e d ) ? ) \/ | .* [ ? & ] v = ) | y o u t u \. b e \/ ) ( [ ^ " & ? \/ \s ] { 11 } ) /
) ?. [ 1 ]
}
setConfig ( newConfig ) {
Object . assign ( this , newConfig )
return this
}
}
// Product.vue
< script setup >
import { computed , ref } from 'vue'
import { MediaTransformer } from '@/services/MediaTransformer'
const props = defineProps(['productGallery', 'product'])
const mediaTransformer = ref(new MediaTransformer({ thumbnailQuality : 'hqdefault' } ))
const mediaObjects = computed(() => {
return mediaTransformer . value . transform ( props . productGallery , props . product ?. product_video )
} )
</ script >
4. JS Třída - Export instance (singleton)
// services/MediaTransformer.js
class MediaTransformer {
constructor ( config = { } ) {
this . thumbnailQuality = config . thumbnailQuality || 'sddefault'
}
transform ( productGallery , productVideos ) {
// stejná implementace jako výše...
}
extractYouTubeId ( url ) {
// stejná implementace...
}
setConfig ( newConfig ) {
Object . assign ( this , newConfig )
return this
}
}
// Export instance
export const mediaTransformer = new MediaTransformer ( )
// Případně export obou
export { MediaTransformer }
// Product.vue
< script setup >
import { computed } from 'vue'
import { mediaTransformer } from '@/services/MediaTransformer'
const props = defineProps(['productGallery', 'product'])
const mediaObjects = computed(() => {
return mediaTransformer . transform ( props . productGallery , props . product ?. product_video )
} )
// Změna konfigurace kdykoliv:
// mediaTransformer.setConfig({ thumbnailQuality : 'maxresdefault' } )
</ script >
// services/MediaTransformer.js
class MediaTransformer {
static _instance = null
constructor ( config = { } ) {
if ( MediaTransformer . _instance ) {
return MediaTransformer . _instance
}
this . thumbnailQuality = config . thumbnailQuality || 'sddefault'
MediaTransformer . _instance = this
}
static getInstance ( config = { } ) {
if ( ! this . _instance ) {
this . _instance = new MediaTransformer ( config )
}
return this . _instance
}
transform ( productGallery , productVideos ) {
// implementace...
}
extractYouTubeId ( url ) {
// implementace...
}
}
export default MediaTransformer
// Product.vue
< script setup >
import { computed } from 'vue'
import MediaTransformer from '@/services/MediaTransformer'
const props = defineProps(['productGallery', 'product'])
const mediaObjects = computed(() => {
const transformer = MediaTransformer . getInstance ( { thumbnailQuality : 'hqdefault' } )
return transformer . transform ( props . productGallery , props . product ?. product_video )
} )
</ script >
// services/MediaTransformer.js
class MediaTransformer {
constructor ( config = { } ) {
this . thumbnailQuality = config . thumbnailQuality || 'sddefault'
}
transform ( productGallery , productVideos ) {
// implementace...
}
extractYouTubeId ( url ) {
// implementace...
}
}
export const createMediaTransformer = ( config = { } ) => {
return new MediaTransformer ( config )
}
// Export i třídy pro pokročilé použití
export { MediaTransformer }
// Product.vue
< script setup >
import { computed , ref } from 'vue'
import { createMediaTransformer } from '@/services/MediaTransformer'
const props = defineProps(['productGallery', 'product'])
const mediaTransformer = ref(createMediaTransformer({ thumbnailQuality : 'maxresdefault' } ))
const mediaObjects = computed(() => {
return mediaTransformer . value . transform ( props . productGallery , props . product ?. product_video )
} )
</ script >
// services/mediaService.js
export const mediaService = {
defaultConfig : {
thumbnailQuality : 'sddefault'
} ,
transform ( productGallery , productVideos , config = { } ) {
const finalConfig = { ...this . defaultConfig , ...config }
const finalObjects = [ ]
if ( productGallery ) {
finalObjects . push (
...productGallery . map ( ( photo , index ) => ( {
...photo ,
type : 'photo' ,
rank : index + 1
} ) )
)
}
if ( productVideos ) {
finalObjects . push (
...productVideos . map ( ( videoUrl , index ) => {
const youtubeId = this . extractYouTubeId ( videoUrl )
return {
url : videoUrl ,
type : 'video' ,
rank : finalObjects . length + index + 1 ,
previewThumb : youtubeId
? `https://img.youtube.com/vi/${ youtubeId } /${ finalConfig . thumbnailQuality } .jpg`
: null
}
} )
)
}
return finalObjects
} ,
extractYouTubeId ( url ) {
return url . match (
/ (?: y o u t u b e \. c o m \/ (?: [ ^ \/ ] + \/ .+ \/ | (?: v | e (?: m b e d ) ? ) \/ | .* [ ? & ] v = ) | y o u t u \. b e \/ ) ( [ ^ " & ? \/ \s ] { 11 } ) /
) ?. [ 1 ]
}
}
// Product.vue
< script setup >
import { computed } from 'vue'
import { mediaService } from '@/services/mediaService'
const props = defineProps(['productGallery', 'product'])
const mediaObjects = computed(() => {
return mediaService . transform (
props . productGallery ,
props . product ?. product_video ,
{ thumbnailQuality : 'hqdefault' }
)
} )
</ script >
8. Pure Functions (Helper)
// utils/mediaTransform.js
export const transformMediaObjects = ( productGallery , productVideos , config = { } ) => {
const { thumbnailQuality = 'sddefault' } = config
const finalObjects = [ ]
if ( productGallery ) {
finalObjects . push (
...productGallery . map ( ( photo , index ) => ( {
...photo ,
type : 'photo' ,
rank : index + 1
} ) )
)
}
if ( productVideos ) {
finalObjects . push (
...productVideos . map ( ( videoUrl , index ) => {
const youtubeId = extractYouTubeId ( videoUrl )
return {
url : videoUrl ,
type : 'video' ,
rank : finalObjects . length + index + 1 ,
previewThumb : youtubeId
? `https://img.youtube.com/vi/${ youtubeId } /${ thumbnailQuality } .jpg`
: null
}
} )
)
}
return finalObjects
}
export const extractYouTubeId = ( url ) => {
return url . match (
/ (?: y o u t u b e \. c o m \/ (?: [ ^ \/ ] + \/ .+ \/ | (?: v | e (?: m b e d ) ? ) \/ | .* [ ? & ] v = ) | y o u t u \. b e \/ ) ( [ ^ " & ? \/ \s ] { 11 } ) /
) ?. [ 1 ]
}
// Product.vue
< script setup >
import { computed } from 'vue'
import { transformMediaObjects } from '@/utils/mediaTransform'
const props = defineProps(['productGallery', 'product'])
const mediaObjects = computed(() => {
return transformMediaObjects (
props . productGallery ,
props . product ?. product_video ,
{ thumbnailQuality : 'hqdefault' }
)
} )
</ script >
Varianta
Výhody
Nevýhody
Použití
Composable
Vue 3 native, reaktivita, auto-import
Vue specific
Vue 3 projekty
Statické metody
Jednoduché, žádná konfigurace
Není flexibilní
Jednoduché transformace
Export třídy
Flexibilní konfigurace
Musíš vytvářet instance
Různé konfigurace
Export instance
Žádné new
, sdílený stav
Pevná konfigurace
Jednotná konfigurace
Singleton
Jedna instance, lazy loading
Složitější pattern
Globální konfigurace
Factory
Flexibilní vytváření
Extra abstrakce
Komplexní objekty
Plain Object
Jednoduché, framework agnostic
Není OOP
Malé utility
Pure Functions
Nejjednodušší, testovatelné
Žádná organizace
Funkcionální přístup
Pro jednoduché transformace : Pure Functions nebo Statické metody
Pro flexibilní konfiguraci : Export třídy nebo Factory
Pro Vue 3 projekty : Composable
Pro globální použití : Export instance s setConfig