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

Soubory cookies

Používáme cookies pro zlepšení vašeho zážitku, pamatování preferencí a analýzu návštěvnosti. Některé cookies jsou nezbytné pro správnou funkci webu.

Nezbytné: Fungování webu, preferences (tmavý režim, zobrazení barvy)
Funkční: Sledování likes, zabránění duplicitním hodnocením