Vue komponenta s pokročilými technikami
Vue.js 📄 AdvancedComponent.vue
Pokročilá Vue komponenta demonstrující Suspense, dynamic components, slots, provide/inject a TypeScript
Vue komponenta s pokročilými technikami
<template>
<div class="advanced-component">
<!-- Conditional rendering s v-show pro výkon -->
<Transition name="fade" appear>
<div v-show="isVisible" class="content">
<h2>{{ title }}</h2>
<!-- Dynamic component s error boundary -->
<Suspense>
<template #default>
<component
:is="currentComponent"
v-bind="componentProps"
@update="handleUpdate"
/>
</template>
<template #fallback>
<div class="loading">Načítání...</div>
</template>
</Suspense>
<!-- Slot s fallback obsahem -->
<div class="slot-content">
<slot name="header" :data="slotData">
<h3>Výchozí header</h3>
</slot>
<slot :items="filteredItems">
<p>Žádný obsah k zobrazení</p>
</slot>
</div>
</div>
</Transition>
</div>
</template>
<script setup lang="ts">
import { ref, computed, provide, inject, watchEffect } from "vue"
import type { Component } from "vue"
interface Props {
title: string
items?: any[]
componentType?: string
}
interface Emits {
(e: "update", value: any): void
(e: "change", id: string): void
}
// Props s default hodnotami
const props = withDefaults(defineProps<Props>(), {
title: "Výchozí nadpis",
items: () => [],
componentType: "default"
})
// Emits
const emit = defineEmits<Emits>()
// Reactive data
const isVisible = ref(true)
const searchTerm = ref("")
// Computed properties
const filteredItems = computed(() => {
if (!searchTerm.value) return props.items
return props.items.filter(item =>
item.name?.toLowerCase().includes(searchTerm.value.toLowerCase())
)
})
const currentComponent = computed((): Component | string => {
const components = {
list: () => import("./ListComponent.vue"),
grid: () => import("./GridComponent.vue"),
default: "div"
}
return components[props.componentType] || components.default
})
const componentProps = computed(() => ({
items: filteredItems.value,
variant: "primary"
}))
const slotData = computed(() => ({
count: filteredItems.value.length,
hasItems: filteredItems.value.length > 0
}))
// Methods
const handleUpdate = (value: any) => {
emit("update", value)
}
const toggleVisibility = () => {
isVisible.value = !isVisible.value
}
// Provide/Inject pro sdílení dat
provide("searchTerm", searchTerm)
provide("toggleVisibility", toggleVisibility)
// Lifecycle & Watchers
watchEffect(() => {
// Side effect při změně filteredItems
if (filteredItems.value.length === 0) {
console.log("Žádné položky k zobrazení")
}
})
// Expose methods pro parent komponentu
defineExpose({
toggleVisibility,
filteredItems
})
</script>
<style scoped>
.advanced-component {
padding: 1rem;
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
.loading {
display: flex;
align-items: center;
justify-content: center;
padding: 2rem;
color: #666;
}
</style>
Informace o gistu
ID:#17
Jazyk:Vue.js
Soubor:AdvancedComponent.vue
Vytvořeno:1. srpna 2025
Likes:0