Bild von Saeid Samani
Saeid Samani
Saeid Samani ist Webentwickler, kreativer Denker und Unternehmer mit einem tiefen Verständnis für digitale Prozesse und moderne Webtechnologien. Er entwickelt durchdachte Webanwendungen, optimierte Benutzererlebnisse und skalierbare Lösungen, die Design, Funktionalität und Strategie miteinander verbinden. In seinem Blog teilt Saeid seine Erfahrungen aus der täglichen Praxis – von sauberem Code und effizientem Workflow bis hin zu Themen rund um Webentwicklung, Automatisierung und digitale Trends. Sein Stil: klar, pragmatisch und immer mit dem Ziel, Wissen greifbar und anwendbar zu machen. Abseits der Arbeit liebt er es, Neues zu lernen, Ideen auszuprobieren und Wege zu finden, Technologie sinnvoll im Alltag einzusetzen.

Teil 2 – Vue 3 Entwicklungsumgebung mit Vite und Pinia

Im zweiten Teil unserer Serie zur modernen Vue-Entwicklung lernen Sie, wie Sie Pinia als zentrales State-Management-System in Ihr Vite-Projekt integrieren, den ersten Store anlegen und ihn in verschiedenen Komponenten verwenden. Außerdem erweitern Sie Ihre Anwendung um den Vue Router, um echte Navigation zwischen mehreren Views zu ermöglichen. Damit ist Ihr Setup bereit für komplexere Strukturen, dynamische Ansichten und eine saubere Trennung von Logik und Darstellung.

Inhaltsverzeichnis

Pinia im Entry-Point einbinden

Was ist Pinia – und warum ist es sinnvoll?
Pinia ist das offizielle State-Management-System für Vue 3 und der Nachfolger von Vuex.
Es dient dazu, Zustände zentral zu verwalten, also Daten, auf die mehrere Komponenten gleichzeitig zugreifen oder die sie verändern müssen – beispielsweise Benutzerinformationen, API-Daten oder UI-Status.
Anstatt Werte über Props und Events zwischen Komponenten zu verschachteln, bietet Pinia eine einfache, reaktive und typsichere Lösung.

Vorteile von Pinia:

  • Offiziell vom Vue-Team entwickelt und optimal in Vue 3 integriert
  • Native TypeScript-Unterstützung
  • Reaktive State-Verwaltung mit klarer Syntax
  • Kompatibel mit Vue Router und der Composition API
  • Leichtgewichtig und dennoch skalierbar für große Projekte

Pinia ist einfach nur eine lib, Sie mussen sie im main.ts (oder main.js) registrieren.

npm install pinia

Öffnen Sie die Hauptdatei (main.ts oder main.js) Ihres Projekts und importieren Sie Pinia. Anschließend erstellen Sie eine Instanz und registrieren sie in Ihrer Vue-App. Falls Sie bereits den Router verwenden, können Sie ihn gleich mit einbinden:

import { createApp } from 'vue'
import { createPinia } from 'pinia'
import './style.css'
import App from './App.vue'

const app = createApp(App)

const pinia = createPinia()
app.use(pinia)

app.mount('#app')

Erste Pinia-Store-Datei anlegen und in einer Komponente verwenden

Nachdem Pinia in Ihrem Projekt eingebunden ist, legen Sie nun den ersten Store an.
Ein Store dient als zentrale Quelle für Zustände (States), abgeleitete Werte (Getters) und Funktionen (Actions). Dadurch können Sie Daten und Logik an einem Ort bündeln – klar strukturiert und wiederverwendbar.

Erstellen Sie im Projektverzeichnis einen neuen Ordner stores (sofern noch nicht vorhanden) und legen Sie darin die Datei counter.ts an.
Ein Beispiel-Store könnte wie folgt aussehen:

import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0,
  }),
  getters: {
    double: (state) => state.count * 2,
  },
  actions: {
    increment() {
      this.count++
    },
  },
})

Erläuterung:

  • state enthält Ihre reaktiven Daten. Hier wird eine einfache Variable count definiert.
  • getters sind vergleichbar mit berechneten Eigenschaften (computed properties) und liefern abgeleitete Werte. In diesem Fall wird double automatisch neu berechnet, sobald sich count ändert.
  • actions sind Methoden, mit denen Sie den State verändern – z. B. durch API-Aufrufe oder Logik, die mehrere Werte gleichzeitig anpasst.

Store in einer Komponente benutzen

Sobald der Store erstellt und global registriert wurde, können Sie ihn in jeder beliebigen Vue-Komponente verwenden.
Importieren Sie dazu einfach den Store und greifen Sie direkt auf seine Werte und Methoden zu.

Ein Beispiel in der App.vue oder einer beliebigen Komponente:

<script setup lang="ts">
import {useCounterStore} from "./stores/counter.ts"
const counter = useCounterStore()
function add() {
  counter.increment()
}
</script>

<template>
  <div>
    <h1>Counter: {{ counter.count }}</h1>
    <p>Double: {{ counter.double }}</p>
    <button @click="add">+1</button>
  </div>

</template>

<style scoped>

</style>

Wie es funktioniert:

  • Mit useCounterStore() holen Sie sich eine Instanz des Stores – vollständig reaktiv.
  • Änderungen an counter.count werden automatisch im Template aktualisiert.
  • Getter wie counter.double verhalten sich wie computed-Properties.
  • Aktionen (hier increment()) führen Änderungen sicher und zentral durch.

Damit ist der grundlegende Aufbau abgeschlossen.
Im nächsten Schritt können Sie weitere Stores anlegen, gemeinsame Zustände aufteilen oder Ihren Store mit echten WordPress-API-Daten verbinden, die Sie später über eine .env-Datei konfigurieren.

Vue Router dazunehmen

In einer modernen Single-Page-Application (SPA) übernimmt der Vue Router die Navigation zwischen verschiedenen Seiten und Komponenten.
Anstatt jede Seite als eigene HTML-Datei zu laden, werden mit Vue Router Routen dynamisch innerhalb der Anwendung gewechselt – schnell, ohne Neuladen und perfekt für SEO-optimierte Strukturen mit klar definierten URLs.

Mit dem Router können Sie mehrere Views (Ansichten) definieren, etwa eine Startseite, eine Detailansicht oder ein Dashboard. Jede Route wird dabei mit einer Vue-Komponente verknüpft. So behalten Sie Übersicht, wenn Ihre Anwendung wächst, und trennen Layout, Daten und Logik sauber voneinander.

Installation

Führen Sie im Projektverzeichnis folgenden Befehl aus:

npm install vue-router

Damit installieren Sie das offizielle Routing-Paket für Vue 3.

Vorbereitung des Projekts für den nächsten Level

Bevor wir den Vue Router in die bestehende Anwendung integrieren, erweitern wir zunächst unser Ziel:
Der bisherige Store soll nicht nur einen Wert verdoppeln, sondern zusätzlich auch eine dreifache Berechnung ermöglichen. Das klingt nach einem kleinen Schritt, ist aber didaktisch wichtig, weil dabei sehr gut sichtbar wird, wie Pinia arbeitet.

Zur Erinnerung:
Mit Pinia speichern wir den Zählerwert (count) zentral im Store. Das bedeutet:
Wenn der Wert in einer Komponente erhöht wird, ist er in allen anderen Komponenten sofort aktualisiert – unabhängig davon, ob diese direkt verwandt sind oder nicht. Genau das unterscheidet ein globales State-Management von klassischen Prop-Ketten.

Damit wir das demonstrieren können – z. B. einmal in App.vue mit Double und auf einer eigenen Route mit Trippel – ergänzen wir unseren Store um eine weitere abgeleitete Eigenschaft.

Öffnen Sie Ihre Datei src/stores/counter.ts und ergänzen Sie die Getter:

trippel: (state) => state.count * 3

Was haben wir damit erreicht?

  • double können Sie wie bisher in App.vue anzeigen.
  • triple können Sie in einer anderen Komponente (z. B. TrippelView.vue, die später über den Router geladen wird) verwenden.
  • Beide greifen auf denselben State (count) zu. Wenn Sie also in App.vue auf „+1“ klicken, sieht auch die TrippelView sofort den neuen Wert.

Genau das ist der Effekt, den wir gleich mit dem Router sichtbar machen wollen: ein globaler Store + mehrere Views = eine konsistente Anwendung.

Router in der App „ins Leben rufen“

Um den Router in Ihrer Anwendung zum Leben zu erwecken, legen Sie zunächst eine neue Datei mit dem Namen index.ts im Verzeichnis /src/router/ an.
Darin definieren Sie alle Navigationspunkte (Routen), also die Verbindungen zwischen bestimmten URLs und den zugehörigen Vue-Komponenten.

Mit diesem Schritt machen Sie Ihre Anwendung multiseitenfähig, ohne dass echte Seiten neu geladen werden müssen – ein zentraler Vorteil einer modernen Single-Page-Application (SPA).

Struktur-Empfehlung:

Es ist sinnvoll, für jede Route eine eigene View-Komponente anzulegen.
So bleibt der Code übersichtlich, und jede Seite kann ihre eigene Logik und Darstellung enthalten.
Diese Views speichern Sie idealerweise im Verzeichnis /src/views/ und geben ihnen sprechende Namen, wie zum Beispiel HomeView.vue oder TrippelView.vue.

Beispiel: HomeView.vue

<script setup lang="ts">
import { useCounterStore } from "../stores/counter"

const counter = useCounterStore()

function add() {
  counter.increment()
}
</script>

<template>
  <div>
    <h1>Counter: {{ counter.count }}</h1>
    <p>Double: {{ counter.double }}</p>
    <button @click="add">+1</button>
  </div>
</template>

<style scoped>

</style>

Beispiel: TrippelView.vue

<script setup lang="ts">
import { useCounterStore } from '../stores/counter'

const counter = useCounterStore()

function add() {
  counter.increment()
}
</script>

<template>
  <div>
    <h1>Counter: {{ counter.count }}</h1>
    <p>Trippel: {{ counter.trippel }}</p>
    <button @click="add">+1</button>
  </div>
</template>

Da wir nun zwei verschiedene View-Komponenten für unsere Navigation angelegt haben – eine für die Startseite (HomeView.vue) und eine für die dreifache Berechnung (TrippelView.vue) – ist es an der Zeit, auch den Router sauber zu strukturieren.

Neues Verzeichnis: router

Anstatt die Routen direkt in der Hauptdatei (main.ts) zu definieren, empfiehlt es sich, dafür ein eigenes Verzeichnis zu verwenden.
So bleibt Ihr Projekt klar gegliedert, und das Routing-Verhalten lässt sich bei wachsenden Anwendungen leichter erweitern oder warten.

Erstellen Sie im Projektverzeichnis /src/ einen neuen Ordner mit dem Namen router.
Darin legen Sie eine Datei index.ts an, die alle Ihre Routen und das Router-Verhalten zentral bündelt.

Beispiel: Router-Datei index.ts

import { createRouter, createWebHistory } from 'vue-router'
import HomeView from "../views/HomeView.vue"
import TrippelView from "../views/TrippelView.vue"

const router = createRouter({
    history: createWebHistory(),
    routes: [
        { path: '/', name: 'home', component: HomeView },
        { path: '/trippel', name: 'trippel', component: TrippelView },
    ],
})

export default router

Erläuterung:

  • Das neue Verzeichnis router dient als zentrale Schaltstelle für alle Navigationsrouten.
  • Durch createRouter() und createWebHistory() aktivieren Sie das Routing im modernen SPA-Stil – also ohne Hash-Symbole in der URL.
  • Jede Route verweist auf eine eigene View-Komponente, die Sie unter /src/views/ ablegen.

Router in der App aktivieren

Damit der Router tatsächlich aktiv ist, müssen Sie ihn in Ihrer Hauptdatei (main.ts) einbinden:

import { createApp } from 'vue'
import { createPinia } from 'pinia'
import router from "./router/index.ts"; //<= NEW
import './style.css'
import App from './App.vue'

const app = createApp(App)

const pinia = createPinia()
app.use(pinia)
app.use(router) //<= NEW

app.mount('#app')

Vorteile dieser Struktur:

  • Das Projekt bleibt übersichtlich und skalierbar, besonders bei mehreren Routen.
  • Änderungen am Navigationsverhalten lassen sich zentral in router/index.ts umsetzen.
  • Ideal für künftige Erweiterungen wie authentifizierte Bereiche, dynamische Parameter oder WordPress-API-basierte Inhalte.

Router in der App aktivieren und zentrale Struktur aufräumen

Als letzten Schritt für den Einsatz des Routers nehmen wir Änderungen an der App.vue vor.
Diese Datei ist das Herzstück Ihrer Anwendung und fungiert als zentraler Einstiegspunkt für alle Views.
Da Sie nun Ihre Logik und Berechnungen (z. B. den Counter) in separaten Komponenten – also HomeView.vue und TrippelView.vue – ausgelagert haben, können Sie Ihre App.vue deutlich vereinfachen und bereinigen.

Ersetzen Sie den bisherigen Inhalt Ihrer App.vue durch folgenden Code:

<script setup lang="ts">

</script>

<template>
  <div>
    <RouterView />
    <hr>
    <nav>
      <RouterLink to="/">Home</RouterLink> |
      <RouterLink to="/trippel">Trippel-View</RouterLink>
    </nav>
  </div>
</template>

<style scoped>

</style>

Erklärung des Codes

  • <RouterView />
    Diese Komponente ist der Platzhalter für die aktuell aktive Route.
    Wenn Sie auf den Link „Home“ klicken, wird automatisch die Komponente HomeView.vue geladen.
    Wechseln Sie auf „Trippel-View“, zeigt Vue Router stattdessen TrippelView.vue an – alles ohne Seitenreload.
  • <RouterLink>
    Mit diesen Komponenten erstellen Sie interne Navigationslinks, die auf die in Ihrer router/index.ts definierten Pfade zeigen.
    • to="/" ruft die Home-Ansicht auf.
    • to="/trippel" öffnet die Seite mit der dreifachen Berechnung.
      Vue Router sorgt dabei dafür, dass sich die URL im Browser anpasst und gleichzeitig der passende Inhalt im <RouterView> angezeigt wird.
  • <hr> und <nav>
    Dienen hier nur zur besseren Strukturierung und Lesbarkeit. Das <hr> trennt optisch den Hauptinhalt von der Navigation, während <nav> Ihre Navigationslinks bündelt.

Zusammenfassung des gesamten Beitrags

In diesem Beitrag haben Sie Schritt für Schritt gesehen, wie aus einer einfachen Vue-3-Anwendung eine solide, erweiterbare Struktur entsteht:

  1. Pinia einbinden – Sie haben das offizielle State-Management-System in den Entry-Point integriert, um globale Zustände zentral zu verwalten.
  2. Ersten Store anlegen – Mit einem einfachen Counter-Store haben Sie die Grundlagen für reaktive Daten, Getter und Actions geschaffen.
  3. Store in Komponenten nutzen – Sie haben gelernt, wie Sie den globalen Zustand in beliebigen Komponenten abrufen und ändern können.
  4. Store erweitern – Der Counter wurde um eine zusätzliche Berechnung (Trippel) ergänzt, um die Wiederverwendbarkeit von Pinia zu verdeutlichen.
  5. Vue Router einführen – Sie haben Navigation und Routen definiert, um mehrere Views sauber zu trennen und miteinander zu verbinden.
  6. App-Struktur optimieren – Die App.vue wurde bereinigt und dient nun als zentrale Steuerung mit <RouterView> und <RouterLink> für die Navigation.

Mit dieser Grundlage ist Ihr Projekt technisch sauber aufgebaut und optimal vorbereitet, um im nächsten Schritt echte Inhalte und API-Daten einzubinden – zum Beispiel aus einem WordPress-Backend oder einem anderen Headless-CMS.