Skip to content

Kapitel 12: Praxisprojekt - Unternehmenswebsite

In diesem Kapitel bauen wir eine professionelle Unternehmenswebsite mit Nuxt 3.


12.1 Projektarchitektur designen

Funktionen:

  • ✅ Responsive Design (Mobile-First)
  • ✅ SEO-optimiert (SSR)
  • ✅ Kontaktformular
  • ✅ Animieren (Scroll-Animationen)
  • ✅ Performance-optimiert (Lazy Loading)

Verzeichnisstruktur:

meine-firma/
├── components/
│   ├── AppHeader.vue
│   ├── AppFooter.vue
│   ├── HeroSection.vue
│   ├── ServicesSection.vue
│   ├── PortfolioSection.vue
│   └── ContactForm.vue
├── pages/
│   ├── index.vue          → Startseite
│   ├── about.vue          → Über uns
│   ├── services.vue       → Leistungen
│   ├── portfolio.vue      → Referenzen
│   └── contact.vue       → Kontakt
├── public/
│   ├── images/
│   │   ├── hero-bg.jpg
│   │   ├── logo.png
│   │   └── ...
│   └── favicon.ico
├── assets/
│   └── scss/
│       ├── main.scss
│       └── _variables.scss
├── layouts/
│   └── default.vue
├── app.vue
├── nuxt.config.ts
└── package.json

12.2 Layout erstellen (layouts/default.vue)

vue
<template>
  <div class="default-layout">
    <!-- Header -->
    <AppHeader />

    <!-- Hauptinhalt -->
    <main>
      <slot />
    </main>

    <!-- Footer -->
    <AppFooter />
  </div>
</template>

<script setup>
// Keine Imports nötig (Auto-Import!)
</script>

<style scoped>
.default-layout {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

main {
  flex: 1;
}
</style>

12.3 Header-Komponente (components/AppHeader.vue)

vue
<script setup>
const isMenuOpen = ref(false)

const navigation = [
  { name: 'Startseite', to: '/' },
  { name: 'Über uns', to: '/about' },
  { name: 'Leistungen', to: '/services' },
  { name: 'Portfolio', to: '/portfolio' },
  { name: 'Kontakt', to: '/contact' }
]

const toggleMenu = () => {
  isMenuOpen.value = !isMenuOpen.value
}
</script>

<template>
  <header class="app-header">
    <div class="header-container">
      <!-- Logo -->
      <NuxtLink to="/" class="logo">
        <img src="/images/logo.png" alt="Firmenlogo" />
        <span>Meine Firma</span>
      </NuxtLink>

      <!-- Desktop-Navigation -->
      <nav class="desktop-nav">
        <NuxtLink
          v-for="item in navigation"
          :key="item.to"
          :to="item.to"
          class="nav-link"
        >
          {{ item.name }}
        </NuxtLink>
      </nav>

      <!-- Mobile Menu Button -->
      <button class="mobile-menu-btn" @click="toggleMenu">
        <span></span>
        <span></span>
        <span></span>
      </button>
    </div>

    <!-- Mobile Navigation -->
    <nav v-if="isMenuOpen" class="mobile-nav">
      <NuxtLink
        v-for="item in navigation"
        :key="item.to"
        :to="item.to"
        class="nav-link"
        @click="isMenuOpen = false"
      >
        {{ item.name }}
      </NuxtLink>
    </nav>
  </header>
</template>

<style scoped>
.app-header {
  background: white;
  box-shadow: 0 2px 10px rgba(0,0,0,0.1);
  position: sticky;
  top: 0;
  z-index: 100;
}

.header-container {
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 20px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 70px;
}

.logo {
  display: flex;
  align-items: center;
  gap: 10px;
  text-decoration: none;
  color: #333;
  font-weight: bold;
  font-size: 1.2em;
}

.logo img {
  height: 40px;
}

.desktop-nav {
  display: flex;
  gap: 30px;
}

.nav-link {
  text-decoration: none;
  color: #333;
  font-weight: 500;
  transition: color 0.3s;
}

.nav-link:hover {
  color: #00dc82;
}

.mobile-menu-btn {
  display: none;
  flex-direction: column;
  gap: 5px;
  background: none;
  border: none;
  cursor: pointer;
}

.mobile-menu-btn span {
  width: 25px;
  height: 3px;
  background: #333;
}

.mobile-nav {
  display: none;
  flex-direction: column;
  padding: 20px;
  gap: 15px;
}

@media (max-width: 768px) {
  .desktop-nav {
    display: none;
  }

  .mobile-menu-btn {
    display: flex;
  }

  .mobile-nav {
    display: flex;
  }
}
</style>

12.4 Hero-Sektion (components/HeroSection.vue)

vue
<template>
  <section class="hero-section">
    <div class="hero-container">
      <div class="hero-content">
        <h1 class="hero-title">
          Willkommen bei <span class="highlight">Meine Firma</span>
        </h1>
        <p class="hero-subtitle">
          Wir bieten erstklassige Webentwicklungsdienstleistungen
        </p>
        <div class="hero-buttons">
          <NuxtLink to="/services" class="btn-primary">
            Unsere Leistungen
          </NuxtLink>
          <NuxtLink to="/contact" class="btn-secondary">
            Kontakt aufnehmen
          </NuxtLink>
        </div>
      </div>
      <div class="hero-image">
        <img src="/images/hero-bg.jpg" alt="Hero Bild" />
      </div>
    </div>
  </section>
</template>

<style scoped>
.hero-section {
  background: linear-gradient(135deg, #00dc82, #007aff);
  color: white;
  padding: 100px 20px;
}

.hero-container {
  max-width: 1200px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  gap: 50px;
}

.hero-content {
  flex: 1;
}

.hero-title {
  font-size: 3em;
  margin-bottom: 20px;
  line-height: 1.2;
}

.highlight {
  color: #ffd700;
}

.hero-subtitle {
  font-size: 1.2em;
  margin-bottom: 30px;
  opacity: 0.9;
}

.hero-buttons {
  display: flex;
  gap: 20px;
}

.btn-primary {
  background: white;
  color: #00dc82;
  padding: 12px 30px;
  border-radius: 5px;
  text-decoration: none;
  font-weight: bold;
  transition: transform 0.3s;
}

.btn-primary:hover {
  transform: translateY(-2px);
}

.btn-secondary {
  background: transparent;
  color: white;
  padding: 12px 30px;
  border: 2px solid white;
  border-radius: 5px;
  text-decoration: none;
  font-weight: bold;
  transition: all 0.3s;
}

.btn-secondary:hover {
  background: white;
  color: #00dc82;
}

.hero-image {
  flex: 1;
  text-align: center;
}

.hero-image img {
  max-width: 100%;
  border-radius: 10px;
  box-shadow: 0 10px 30px rgba(0,0,0,0.3);
}

@media (max-width: 768px) {
  .hero-container {
    flex-direction: column;
    text-align: center;
  }

  .hero-title {
    font-size: 2em;
  }

  .hero-buttons {
    justify-content: center;
  }
}
</style>

12.5 Startseite (pages/index.vue)

vue
<script setup>
// SEO-Konfiguration
useSeoMeta({
  title: 'Startseite',
  description: 'Willkommen bei Meine Firma - Ihr Partner für Webentwicklung',
  ogTitle: 'Meine Firma - Webentwicklung',
  ogDescription: 'Professionelle Webentwicklungsdienstleistungen',
  ogImage: 'https://meine-firma.de/images/og-image.jpg'
})
</script>

<template>
  <div class="home-page">
    <!-- Hero-Sektion -->
    <HeroSection />

    <!-- Leistungen -->
    <ServicesSection />

    <!-- Portfolio -->
    <PortfolioSection />

    <!-- Kontakt CTA -->
    <section class="cta-section">
      <div class="cta-container">
        <h2>Bereit für Ihr nächstes Projekt?</h2>
        <p>Kontaktieren Sie uns noch heute!</p>
        <NuxtLink to="/contact" class="cta-button">
          Jetzt anfragen
        </NuxtLink>
      </div>
    </section>
  </div>
</template>

<style scoped>
.cta-section {
  background: #f5f5f5;
  padding: 80px 20px;
  text-align: center;
}

.cta-container {
  max-width: 800px;
  margin: 0 auto;
}

.cta-container h2 {
  font-size: 2.5em;
  margin-bottom: 20px;
  color: #333;
}

.cta-container p {
  font-size: 1.2em;
  margin-bottom: 30px;
  color: #666;
}

.cta-button {
  display: inline-block;
  background: #00dc82;
  color: white;
  padding: 15px 40px;
  border-radius: 5px;
  text-decoration: none;
  font-weight: bold;
  font-size: 1.1em;
  transition: all 0.3s;
}

.cta-button:hover {
  background: #00c476;
  transform: translateY(-2px);
}
</style>

12.6 SEO-Optimierung

Globale Meta-Konfiguration (app.vue):

vue
<script setup>
useHead({
  titleTemplate: '%s - Meine Firma',
  meta: [
    { name: 'description', content: 'Professionelle Webentwicklungsdienstleistungen' },
    { name: 'keywords', content: 'Webentwicklung, Vue.js, Nuxt 3, SEO' },
    { property: 'og:type', content: 'website' },
    { property: 'og:site_name', content: 'Meine Firma' }
  ],
  link: [
    { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
    { rel: 'canonical', href: 'https://meine-firma.de' }
  ],
  script: [
    {
      type: 'application/ld+json',
      children: JSON.stringify({
        '@context': 'https://schema.org',
        '@type': 'Organization',
        name: 'Meine Firma',
        url: 'https://meine-firma.de',
        logo: 'https://meine-firma.de/images/logo.png'
      })
    }
  ]
})
</script>

<template>
  <NuxtPage />
</template>

12.7 Performance-Optimierung

Bild-Optimierung mit <NuxtImg>:

bash
# Modul installieren
pnpm add @nuxt/image

In nuxt.config.ts:

typescript
export default defineNuxtConfig({
  modules: [
    '@nuxt/image'
  ],
  image: {
    screens: {
      sm: 640,
      md: 768,
      lg: 1024
    }
  }
})

Verwendung:

vue
<template>
  <NuxtImg
    src="/images/hero.jpg"
    alt="Hero Bild"
    format="webp"
    quality="80"
    loading="lazy"
    sizes="sm:100px md:500px lg:1000px"
  />
</template>

12.8 Zusammenfassung

In diesem Kapitel haben Sie gelernt:

  • ✅ Eine Unternehmenswebsite mit Nuxt 3 zu bauen
  • ✅ Layouts & Komponenten zu strukturieren
  • ✅ Responsive Header & Hero-Sektion zu erstellen
  • ✅ SEO mit useSeoMeta() zu optimieren
  • ✅ Performance-Optimierung (Bild-Optimierung)

Nächste Schritte: Im nächsten Kapitel lernen wir erweiterte Konfiguration & Optimierung für Nuxt 3.


📚 Weiterführende Ressourcen


Nächstes Kapitel: Kapitel 13: Erweiterte Konfiguration & Optimierung →

Frei für alle Anfänger