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(
/(?:youtube\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/\s]{11})/
)?.[1]
}
return {
transformMediaObjects,
extractYouTubeId
}
}
Použití v komponentě:
// 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(
/(?:youtube\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/\s]{11})/
)?.[1]
}
static generateThumbnail(youtubeId, quality = 'sddefault') {
return `https://img.youtube.com/vi/${youtubeId}/${quality}.jpg`
}
}
Použití:
// 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(
/(?:youtube\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/\s]{11})/
)?.[1]
}
setConfig(newConfig) {
Object.assign(this, newConfig)
return this
}
}
Použití:
// 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 }
Použití:
// 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>
5. Singleton Pattern
// 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
Použití:
// 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>
5.1 Singleton with Registry
class MediaTransformer {
static _instances = new Map()
constructor(config = {}) {
this.thumbnailQuality = config.thumbnailQuality || 'sddefault'
this.config = config
}
static getInstance(config = {}) {
// Vytvoř unikátní klíč z configu
const key = JSON.stringify(config)
if (!this._instances.has(key)) {
this._instances.set(key, new MediaTransformer(config))
}
return this._instances.get(key)
}
transform(productGallery, productVideos) {
// implementace...
}
}
const hq = MediaTransformer.getInstance({ thumbnailQuality: 'hqdefault' })
const max = MediaTransformer.getInstance({ thumbnailQuality: 'maxresdefault' })
// Různé instance ✅
5.2 New class with static fn
class MediaTransformer {
constructor(config = {}) {
this.thumbnailQuality = config.thumbnailQuality || 'sddefault'
}
transform(productGallery, productVideos) {
// implementace...
}
static transform(productGallery, productVideos, config = {}) {
const instance = new MediaTransformer(config)
return instance.transform(productGallery, productVideos)
}
}
export default MediaTransformer
// Varianta 1: Instance
const transformer = new MediaTransformer({ thumbnailQuality: 'hqdefault' })
const media = transformer.transform(gallery, videos)
// Varianta 2: Statická metoda
const media = MediaTransformer.transform(gallery, videos, { thumbnailQuality: 'hqdefault' })
6. Factory Function
// 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 }
Použití:
// 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>
7. Plain Object/Service
// 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(
/(?:youtube\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/\s]{11})/
)?.[1]
}
}
Použití:
// 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(
/(?:youtube\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/\s]{11})/
)?.[1]
}
Použití:
// 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>
Srovnání variant
| 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 |
Doporučení
- 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