Wichtige Vue.js-Interviewfragen: 25 Fragen für den Job

Vorbereitung auf Vue.js-Interviews mit diesen 25 wichtigen Fragen. Von Reaktivität bis zu Composables die Schlüsselkonzepte für das nächste Gespräch.

Illustration eines technischen Vue.js-Interviews mit Codeblöcken und Vue-Logo

Vue.js-Interviews bewerten weit mehr als nur die Framework-Syntax. Recruiter wollen verstehen, wie sicher Kandidaten das Reaktivitätssystem beherrschen, wie sie ihren Code mit der Composition API organisieren und ob sie reale Performance- und Architekturprobleme lösen können.

Vorbereitungstipp

Jede Frage enthält eine ausführliche Antwort und Codebeispiele. Für technische Interviews empfiehlt es sich, die Konzepte laut zu erklären, wie in einem echten Gespräch.

Grundlegende Vue.js-Fragen

1. Was ist der Unterschied zwischen ref und reactive in Vue 3?

Diese Frage prüft das Verständnis des Reaktivitätssystems, einer Kerneigenschaft von Vue 3. Der Hauptunterschied liegt in den verarbeiteten Datentypen und der Zugriffssyntax.

ref erzeugt eine reaktive Referenz für primitive Werte (string, number, boolean) und benötigt .value, um im Skript auf den Wert zuzugreifen. reactive erzeugt einen reaktiven Proxy für Objekte und erlaubt direkten Zugriff auf die Eigenschaften.

javascript
// Vergleichsbeispiel ref vs reactive
import { ref, reactive } from 'vue'

// ref: for primitives
// Requires .value in the script
const count = ref(0)
count.value++ // Access with .value

// reactive: for complex objects
// Direct property access
const user = reactive({
  name: 'Alice',
  age: 25
})
user.age++ // No .value needed

// Warning: reactive loses reactivity if reassigned
// user = { name: 'Bob', age: 30 } // ❌ Breaks reactivity
Object.assign(user, { name: 'Bob', age: 30 }) // ✅ Correct

Allgemeine Regel: ref für einfache Werte verwenden und reactive für strukturierte Objekte mit mehreren zusammenhängenden Eigenschaften.

2. Wie funktioniert das Reaktivitätssystem von Vue 3?

Vue 3 nutzt JavaScript-Proxies (ES6), um Operationen auf reaktiven Objekten abzufangen. Anders als Vue 2, das Object.defineProperty einsetzte, erkennt dieser Ansatz das Hinzufügen und Entfernen von Eigenschaften dynamisch.

javascript
// Simplified demonstration of the reactivity principle
// Vue uses Proxies to track dependencies

const handler = {
  // Intercept reading
  get(target, key, receiver) {
    track(target, key) // Register the dependency
    return Reflect.get(target, key, receiver)
  },
  // Intercept writing
  set(target, key, value, receiver) {
    const result = Reflect.set(target, key, value, receiver)
    trigger(target, key) // Trigger updates
    return result
  }
}

// Creating a reactive proxy
const reactiveObject = new Proxy(originalObject, handler)

Zu den Vorteilen von Proxy zählen: Erkennung neuer Eigenschaften, Unterstützung von Map und Set sowie bessere Performance bei großen Objekten.

3. Erkläre den Unterschied zwischen computed und watch

computed und watch decken unterschiedliche Aufgaben in der Reaktivitätsverwaltung ab.

Computed: berechnet einen abgeleiteten Wert aus anderen reaktiven Daten. Werte werden zwischengespeichert und nur neu berechnet, wenn sich Abhängigkeiten ändern. Ideal für Datentransformationen.

Watch: führt Seiteneffekte als Reaktion auf Änderungen aus. Nützlich für API-Aufrufe, DOM-Interaktionen oder asynchrone Operationen.

javascript
// Computed vs watch comparison
import { ref, computed, watch } from 'vue'

const firstName = ref('John')
const lastName = ref('Doe')

// computed: derived value with cache
// Recalculates only if firstName or lastName changes
const fullName = computed(() => {
  console.log('Computing full name') // Called only once
  return `${firstName.value} ${lastName.value}`
})

// Multiple accesses = single execution (cached)
console.log(fullName.value) // "John Doe"
console.log(fullName.value) // No recalculation

// watch: side effect without cache
// Executed on every change
watch(firstName, async (newName, oldName) => {
  // Side effect: API call
  await saveToServer({ firstName: newName })
  console.log(`Name changed from ${oldName} to ${newName}`)
})

4. Was ist das Virtual DOM und wie nutzt Vue es?

Das Virtual DOM ist eine schlanke JavaScript-Repräsentation des realen DOM. Vue hält einen virtuellen Baum im Speicher und berechnet die Unterschiede (Diffing) zwischen vorherigem und neuem Zustand, um nur die nötigen Änderungen am realen DOM auszuführen.

javascript
// Conceptual representation of the Virtual DOM
// Vue creates this structure internally

const vnode = {
  type: 'div',
  props: {
    class: 'container',
    id: 'app'
  },
  children: [
    {
      type: 'h1',
      props: {},
      children: 'Title'
    },
    {
      type: 'p',
      props: {},
      children: 'Paragraph content'
    }
  ]
}

// When changes occur, Vue compares vnodes
// and updates only the modified elements

Optimierungen in Vue 3 umfassen: Hoisting statischer Knoten, Patch-Flags zur Identifikation von Änderungstypen und Tree-Shaking im Compiler.

5. Wie wird die Kommunikation zwischen Komponenten ohne direkte Beziehung gehandhabt?

Es gibt mehrere Muster, um Komponenten ohne direkte Eltern-Kind-Beziehung miteinander kommunizieren zu lassen.

javascript
// Solution 1: Event Bus (small applications)
// eventBus.js
import { ref } from 'vue'

const bus = ref(new Map())

export function useEventBus() {
  // Emit an event
  const emit = (event, payload) => {
    const callbacks = bus.value.get(event) || []
    callbacks.forEach(cb => cb(payload))
  }

  // Listen to an event
  const on = (event, callback) => {
    if (!bus.value.has(event)) {
      bus.value.set(event, [])
    }
    bus.value.get(event).push(callback)
  }

  return { emit, on }
}
javascript
// Solution 2: Provide/Inject for nested components
// Ancestor
import { provide, ref } from 'vue'

const sharedState = ref('shared value')
provide('stateKey', sharedState)

// Descendant (any level)
import { inject } from 'vue'

const state = inject('stateKey')

Für komplexere Anwendungen bleibt Pinia die empfohlene Lösung für die globale Zustandsverwaltung.

Fragen zur Composition API

6. Welche Vorteile bietet die Composition API gegenüber der Options API?

Die Composition API bietet mehrere strukturelle Vorteile gegenüber der klassischen Options API.

Organisation nach Feature: Code, der zur selben Funktionalität gehört, ist gruppiert, während die Options API nach Typ trennt (data, methods, computed).

Wiederverwendung über Composables: einfache Auslagerung von Logik in wiederverwendbare Funktionen.

Bessere TypeScript-Unterstützung: natürliche Typinferenz ohne Decorators.

javascript
// Options API: code fragmented by type
export default {
  data() {
    return {
      searchQuery: '',
      results: []
    }
  },
  computed: {
    hasResults() {
      return this.results.length > 0
    }
  },
  methods: {
    async search() {
      this.results = await fetchResults(this.searchQuery)
    }
  },
  watch: {
    searchQuery: 'search'
  }
}

// Composition API: code grouped by feature
import { ref, computed, watch } from 'vue'

export function useSearch() {
  const searchQuery = ref('')
  const results = ref([])

  const hasResults = computed(() => results.value.length > 0)

  const search = async () => {
    results.value = await fetchResults(searchQuery.value)
  }

  watch(searchQuery, search)

  return { searchQuery, results, hasResults, search }
}

7. Wie erstellt man einen wiederverwendbaren Composable?

Composables sind Funktionen, die reaktive Logik kapseln. Übliche Konventionen: Präfix use, Rückgabe eines Objekts mit Zustand und Methoden sowie Behandlung des Cleanups.

composables/useLocalStorage.jsjavascript
import { ref, watch } from 'vue'

// Composable to synchronize state with localStorage
export function useLocalStorage(key, defaultValue) {
  // Retrieve initial value from localStorage
  const storedValue = localStorage.getItem(key)
  const data = ref(
    storedValue ? JSON.parse(storedValue) : defaultValue
  )

  // Synchronize changes to localStorage
  watch(
    data,
    (newValue) => {
      if (newValue === null) {
        localStorage.removeItem(key)
      } else {
        localStorage.setItem(key, JSON.stringify(newValue))
      }
    },
    { deep: true } // Observe nested objects
  )

  return data
}

// Usage in a component
const theme = useLocalStorage('theme', 'light')
const userPrefs = useLocalStorage('prefs', { notifications: true })
Namenskonvention

Composables folgen der Konvention useXxx, um ihren wiederverwendbaren Charakter anzuzeigen. Diese Konvention verbessert die Lesbarkeit und erleichtert das Erkennen reaktiver Abhängigkeiten.

8. Erkläre watchEffect gegenüber watch

watchEffect und watch reagieren beide auf Änderungen, jedoch mit unterschiedlichen Ansätzen.

watchEffect: läuft sofort und wird automatisch erneut ausgeführt, sobald sich seine reaktiven Abhängigkeiten ändern. Die Abhängigkeiten werden automatisch verfolgt.

watch: beobachtet bestimmte Quellen und liefert alten und neuen Wert. Bietet mehr Kontrolle darüber, wann ausgelöst wird.

javascript
// watchEffect vs watch comparison
import { ref, watch, watchEffect } from 'vue'

const userId = ref(1)
const userData = ref(null)

// watchEffect: automatic tracking
// Runs immediately
watchEffect(async () => {
  // userId is automatically tracked
  const response = await fetch(`/api/users/${userId.value}`)
  userData.value = await response.json()
})

// watch: explicit sources with old values
watch(userId, async (newId, oldId) => {
  console.log(`User changed from ${oldId} to ${newId}`)
  const response = await fetch(`/api/users/${newId}`)
  userData.value = await response.json()
}, {
  immediate: true // Run immediately like watchEffect
})

// watchEffect with cleanup
watchEffect((onCleanup) => {
  const controller = new AbortController()

  fetch(`/api/users/${userId.value}`, {
    signal: controller.signal
  }).then(/* ... */)

  // Cleanup: cancel previous request
  onCleanup(() => controller.abort())
})

9. Wie behandelt man Props mit TypeScript in script setup?

Die Syntax <script setup> bietet eine native TypeScript-Integration mit defineProps und withDefaults.

TypedComponent.vuetypescript
<script setup lang="ts">
// Interface for props
interface Props {
  title: string
  count?: number
  items?: string[]
  onSubmit?: (data: FormData) => void
}

// defineProps with generic typing
// withDefaults for default values
const props = withDefaults(defineProps<Props>(), {
  count: 0,
  items: () => [], // Factory for objects/arrays
  onSubmit: undefined
})

// Props are automatically typed
console.log(props.title) // string
console.log(props.count) // number

// defineEmits with typing
const emit = defineEmits<{
  (e: 'update', value: number): void
  (e: 'delete', id: string): void
}>()

// Typed emit usage
const handleUpdate = () => {
  emit('update', props.count + 1)
}
</script>

Bereit für deine Vue.js / Nuxt.js-Interviews?

Übe mit unseren interaktiven Simulatoren, Flashcards und technischen Tests.

Performance-Fragen

10. Welche Performance-Optimierungstechniken gibt es?

Vue 3 bietet mehrere Mechanismen zur Performance-Optimierung.

1. v-once: single render for static contentjavascript
<template>
  <div v-once>
    <!-- This content will never be re-rendered -->
    <ComplexStaticComponent />
  </div>
</template>

// 2. v-memo: conditional memoization
<template>
  <div v-for="item in list" :key="item.id" v-memo="[item.id, item.selected]">
    <!-- Re-renders only if id or selected changes -->
    {{ item.name }}
  </div>
</template>

// 3. shallowRef/shallowReactive: shallow reactivity
import { shallowRef, triggerRef } from 'vue'

// Only tracks ref replacement, not internal mutations
const largeList = shallowRef([/* thousands of elements */])

// Force update after mutation
largeList.value.push(newItem)
triggerRef(largeList) // Manually trigger re-render
4. Async components for code-splittingjavascript
import { defineAsyncComponent } from 'vue'

const HeavyComponent = defineAsyncComponent({
  loader: () => import('./HeavyComponent.vue'),
  loadingComponent: LoadingSpinner,
  delay: 200, // Delay before showing loading
  errorComponent: ErrorDisplay,
  timeout: 3000
})

// 5. KeepAlive for component caching
<template>
  <KeepAlive :include="['Dashboard', 'UserProfile']" :max="10">
    <component :is="currentView" />
  </KeepAlive>
</template>

11. Wie vermeidet man unnötige Re-Renders?

Unnötige Re-Renders beeinträchtigen die Performance. Mehrere Strategien helfen, sie zu minimieren.

javascript
// Problem: function created on each render
<template>
  <!--New function on every render -->
  <ChildComponent @click="() => handleClick(item.id)" />
</template>

// Solution: use a method or ref
<script setup>
const handleItemClick = (id) => {
  // Processing logic
}
</script>

<template>
  <!--Stable reference -->
  <ChildComponent @click="handleItemClick(item.id)" />
</template>
javascript
// Using computed for expensive calculations
import { computed } from 'vue'

// ❌ Recalculated on every render
const getFilteredItems = () => {
  return items.value.filter(/* complex logic */)
}

// ✅ Cached, recalculated only if items changes
const filteredItems = computed(() => {
  return items.value.filter(/* complex logic */)
})

12. Erkläre Lazy Loading von Komponenten und Routen

Lazy Loading lädt Code bei Bedarf nach und reduziert so die Größe des initialen Bundles.

router/index.jsjavascript
import { createRouter, createWebHistory } from 'vue-router'

const router = createRouter({
  history: createWebHistory(),
  routes: [
    {
      path: '/',
      // Immediate loading (main bundle)
      component: () => import('@/views/Home.vue')
    },
    {
      path: '/dashboard',
      // Separate chunk with custom name
      component: () => import(
        /* webpackChunkName: "dashboard" */
        '@/views/Dashboard.vue'
      ),
      // Lazy loading child routes
      children: [
        {
          path: 'analytics',
          component: () => import('@/views/Analytics.vue')
        }
      ]
    },
    {
      path: '/admin',
      // Prefetch on link hover
      component: () => import('@/views/Admin.vue'),
      meta: { prefetch: true }
    }
  ]
})

export default router

Fragen zum Vue Router

13. Wie schützt man Routen mit Guards?

Navigation Guards steuern den Zugriff auf Routen.

router/index.jsjavascript
import { createRouter } from 'vue-router'
import { useAuthStore } from '@/stores/auth'

const router = createRouter({
  routes: [
    {
      path: '/dashboard',
      component: Dashboard,
      meta: { requiresAuth: true, roles: ['admin', 'user'] }
    }
  ]
})

// Global guard: checks authentication
router.beforeEach(async (to, from, next) => {
  const auth = useAuthStore()

  // Public route
  if (!to.meta.requiresAuth) {
    return next()
  }

  // Check authentication
  if (!auth.isAuthenticated) {
    return next({
      path: '/login',
      query: { redirect: to.fullPath }
    })
  }

  // Check roles if specified
  if (to.meta.roles && !to.meta.roles.includes(auth.user.role)) {
    return next('/unauthorized')
  }

  next()
})

// Component-level guard
export default {
  beforeRouteEnter(to, from, next) {
    // No access to this here
    next(vm => {
      // Access component instance via vm
      vm.loadData()
    })
  },
  beforeRouteLeave(to, from, next) {
    // Confirm before leaving if form modified
    if (this.hasUnsavedChanges) {
      const answer = confirm('Leave without saving?')
      next(answer)
    } else {
      next()
    }
  }
}

14. Wie übergibt man Props an Routen?

Vue Router ermöglicht es, Komponenten von Routenparametern zu entkoppeln.

javascript
// Route configuration with props
const routes = [
  {
    path: '/user/:id',
    component: UserProfile,
    // Boolean mode: passes params as props
    props: true
  },
  {
    path: '/search',
    component: SearchResults,
    // Function mode: custom transformation
    props: (route) => ({
      query: route.query.q,
      page: parseInt(route.query.page) || 1,
      filters: route.query.filters?.split(',') || []
    })
  },
  {
    path: '/static',
    component: StaticPage,
    // Object mode: static props
    props: { sidebar: true, theme: 'dark' }
  }
]
UserProfile.vuejavascript
<script setup>
// Props are automatically injected
defineProps<{
  id: string
}>()
</script>

// SearchResults.vue
<script setup>
defineProps<{
  query: string
  page: number
  filters: string[]
}>()
</script>

Fragen zu Pinia und State Management

15. Was sind die Unterschiede zwischen Pinia und Vuex?

Pinia ist der offizielle State-Manager für Vue 3 und ersetzt Vuex mit einer vereinfachten API.

| Funktion | Vuex | Pinia | |---------|------|-------| | Mutations | Pflicht | Nicht nötig | | Module | Komplexe Konfiguration | Unabhängige Stores | | TypeScript | Eingeschränkter Support | Nativ und vollständig | | API | Options | Composition + Options | | DevTools | Unterstützt | Voller Support |

javascript
// Pinia Store with Composition API
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'

export const useCartStore = defineStore('cart', () => {
  // State
  const items = ref([])
  const discountCode = ref(null)

  // Getters (computed)
  const totalItems = computed(() =>
    items.value.reduce((sum, item) => sum + item.quantity, 0)
  )

  const totalPrice = computed(() => {
    const subtotal = items.value.reduce(
      (sum, item) => sum + item.price * item.quantity, 0
    )
    return discountCode.value ? subtotal * 0.9 : subtotal
  })

  // Actions (direct functions)
  function addItem(product) {
    const existing = items.value.find(i => i.id === product.id)
    if (existing) {
      existing.quantity++
    } else {
      items.value.push({ ...product, quantity: 1 })
    }
  }

  function removeItem(productId) {
    const index = items.value.findIndex(i => i.id === productId)
    if (index > -1) {
      items.value.splice(index, 1)
    }
  }

  async function checkout() {
    const response = await api.createOrder(items.value)
    items.value = []
    return response
  }

  return {
    items, discountCode,
    totalItems, totalPrice,
    addItem, removeItem, checkout
  }
})

16. Wie persistiert man den Zustand eines Pinia-Stores?

Persistenz erlaubt es, den Zustand zwischen Benutzersitzungen zu erhalten.

plugins/piniaPersistedState.jsjavascript
import { watch } from 'vue'

export function createPersistedState(options = {}) {
  const {
    key = 'pinia',
    storage = localStorage,
    paths = null
  } = options

  return ({ store }) => {
    // Restore state on startup
    const savedState = storage.getItem(`${key}-${store.$id}`)
    if (savedState) {
      store.$patch(JSON.parse(savedState))
    }

    // Persist changes
    watch(
      () => store.$state,
      (state) => {
        const toSave = paths
          ? paths.reduce((acc, path) => {
              acc[path] = state[path]
              return acc
            }, {})
          : state

        storage.setItem(
          `${key}-${store.$id}`,
          JSON.stringify(toSave)
        )
      },
      { deep: true }
    )
  }
}

// main.js
import { createPinia } from 'pinia'
import { createPersistedState } from './plugins/piniaPersistedState'

const pinia = createPinia()
pinia.use(createPersistedState({
  key: 'app-state',
  paths: ['user', 'preferences'] // Persist only these keys
}))
Sensible Daten

Sensible Daten (Tokens, Passwörter) sollten nicht im localStorage abgelegt werden. Für Authentifizierungstoken eignen sich httpOnly-Cookies besser.

Fortgeschrittene Fragen

17. Wie implementiert man ein Plugin-System in Vue?

Plugins erweitern Vue um globale Funktionen.

plugins/analyticsPlugin.jsjavascript
export const AnalyticsPlugin = {
  install(app, options = {}) {
    const { trackingId, debug = false } = options

    // Global injection available in all components
    const analytics = {
      trackEvent(category, action, label) {
        if (debug) {
          console.log('Analytics:', { category, action, label })
        }
        // Logic to send to analytics service
        window.gtag?.('event', action, {
          event_category: category,
          event_label: label
        })
      },
      trackPage(path) {
        window.gtag?.('config', trackingId, { page_path: path })
      }
    }

    // Make available via inject
    app.provide('analytics', analytics)

    // Add global property (discouraged in Composition API)
    app.config.globalProperties.$analytics = analytics

    // Custom directive for click tracking
    app.directive('track', {
      mounted(el, binding) {
        el.addEventListener('click', () => {
          analytics.trackEvent('click', binding.value, el.textContent)
        })
      }
    })

    // Automatic route change tracking
    app.mixin({
      mounted() {
        if (this.$route) {
          analytics.trackPage(this.$route.path)
        }
      }
    })
  }
}

// main.js
import { AnalyticsPlugin } from './plugins/analyticsPlugin'

app.use(AnalyticsPlugin, {
  trackingId: 'UA-XXXXX-X',
  debug: import.meta.env.DEV
})

18. Erkläre Render Functions und ihren Nutzen

Render Functions bieten volle Kontrolle über das Rendering und sind besonders bei sehr dynamischen Komponenten nützlich.

components/DynamicHeading.jsjavascript
import { h } from 'vue'

// Functional component with render function
export const DynamicHeading = {
  props: {
    level: {
      type: Number,
      default: 1,
      validator: (v) => v >= 1 && v <= 6
    }
  },
  setup(props, { slots }) {
    // h() creates a vnode
    // Arguments: type, props, children
    return () => h(
      `h${props.level}`,
      { class: 'dynamic-heading' },
      slots.default?.()
    )
  }
}

// Component with complex conditional logic
export const ConditionalWrapper = {
  props: ['condition', 'wrapper'],
  setup(props, { slots }) {
    return () => {
      if (props.condition) {
        return h(props.wrapper, null, slots.default?.())
      }
      return slots.default?.()
    }
  }
}

// Usage
<DynamicHeading :level="2">Level 2 Title</DynamicHeading>

<ConditionalWrapper :condition="isLink" wrapper="a">
  Conditional content
</ConditionalWrapper>

19. Wie testet man Vue-Komponenten mit Vitest?

Unit-Tests prüfen das isolierte Verhalten von Komponenten.

components/__tests__/Counter.spec.jsjavascript
import { describe, it, expect, vi } from 'vitest'
import { mount } from '@vue/test-utils'
import Counter from '../Counter.vue'

describe('Counter', () => {
  it('displays the initial value', () => {
    const wrapper = mount(Counter, {
      props: { initialValue: 5 }
    })

    expect(wrapper.text()).toContain('5')
  })

  it('increments the value on click', async () => {
    const wrapper = mount(Counter)

    await wrapper.find('button.increment').trigger('click')

    expect(wrapper.text()).toContain('1')
  })

  it('emits an event when changed', async () => {
    const wrapper = mount(Counter)

    await wrapper.find('button.increment').trigger('click')

    expect(wrapper.emitted('change')).toBeTruthy()
    expect(wrapper.emitted('change')[0]).toEqual([1])
  })

  it('calls the service on submit', async () => {
    const mockSubmit = vi.fn()
    const wrapper = mount(Counter, {
      global: {
        provide: {
          submitService: mockSubmit
        }
      }
    })

    await wrapper.find('form').trigger('submit')

    expect(mockSubmit).toHaveBeenCalled()
  })
})

20. Wie behandelt man Fehler global in Vue?

Vue 3 bietet mehrere Mechanismen, um Fehler abzufangen und zu behandeln.

main.jsjavascript
import { createApp } from 'vue'

const app = createApp(App)

// Global handler for component errors
app.config.errorHandler = (err, instance, info) => {
  // err: the error
  // instance: the component instance
  // info: string describing where the error occurred

  console.error('Vue error:', err)
  console.error('Component:', instance?.$options?.name)
  console.error('Info:', info)

  // Send to monitoring service
  errorTracker.captureException(err, {
    component: instance?.$options?.name,
    info
  })
}

// Handler for warnings (dev only)
app.config.warnHandler = (msg, instance, trace) => {
  console.warn('Vue warning:', msg)
}
javascript
// ErrorBoundary component
<script setup>
import { onErrorCaptured, ref } from 'vue'

const error = ref(null)

// Captures errors from child components
onErrorCaptured((err, instance, info) => {
  error.value = {
    message: err.message,
    component: instance?.$options?.name,
    info
  }

  // Return false to stop propagation
  return false
})

const retry = () => {
  error.value = null
}
</script>

<template>
  <div v-if="error" class="error-boundary">
    <h2>An error occurred</h2>
    <p>{{ error.message }}</p>
    <button @click="retry">Retry</button>
  </div>
  <slot v-else />
</template>

Bereit für deine Vue.js / Nuxt.js-Interviews?

Übe mit unseren interaktiven Simulatoren, Flashcards und technischen Tests.

Fragen zu Best Practices

21. Welche Namenskonventionen gelten in Vue?

Namenskonventionen verbessern Lesbarkeit und Wartbarkeit des Codes.

javascript
// Component naming
// PascalCase for files and names
// BaseButton.vue, AppHeader.vue, TheNavbar.vue

// Props: camelCase in JS, kebab-case in template
defineProps<{
  userName: string        // JS
  isActive: boolean       // JS
}>()

// <UserCard :user-name="name" :is-active="active" />

// Events: camelCase with action prefix
const emit = defineEmits<{
  (e: 'updateValue', value: string): void  // ✅
  (e: 'submit'): void                       // ✅
  (e: 'value-updated'): void               // ❌ Avoid
}>()

// Composables: use prefix
// useAuth.js, useFetch.js, useLocalStorage.js

// Pinia stores: use prefix + Store suffix
// useUserStore, useCartStore, useSettingsStore

// Constants: SCREAMING_SNAKE_CASE
const MAX_RETRY_COUNT = 3
const API_BASE_URL = '/api/v1'

22. Wie strukturiert man ein großes Vue-Projekt?

Eine modulare Struktur erleichtert Navigation und Wartung.

text
src/
├── assets/              # Static files
├── components/
│   ├── ui/              # Generic components (Button, Modal)
│   └── common/          # Reusable business components
├── composables/         # Reusable logic
│   ├── useAuth.js
│   └── useFetch.js
├── layouts/             # Page layouts
│   ├── DefaultLayout.vue
│   └── AuthLayout.vue
├── modules/             # Functional modules
│   ├── auth/
│   │   ├── components/
│   │   ├── composables/
│   │   ├── stores/
│   │   └── views/
│   └── dashboard/
├── plugins/             # Vue plugins
├── router/
│   ├── index.js
│   └── guards.js
├── stores/              # Global Pinia stores
├── types/               # TypeScript types
├── utils/               # Pure utilities
└── views/               # Pages/Routes

23. Wann v-if statt v-show verwenden?

Die Wahl zwischen v-if und v-show hängt von der Toggle-Häufigkeit ab.

javascript
// v-if: low initial cost, expensive toggle
// Removes/adds element from DOM
// Ideal for: rarely modified conditions

<template>
  <!-- v-if: component not created if not admin -->
  <AdminPanel v-if="user.isAdmin" />

  <!-- v-if with v-else-if for multiple conditions -->
  <LoadingSpinner v-if="isLoading" />
  <ErrorMessage v-else-if="error" :message="error" />
  <DataDisplay v-else :data="data" />
</template>

// v-show: higher initial cost, fast toggle
// Uses display: none
// Ideal for: frequent toggles

<template>
  <!-- v-show: always rendered, frequent toggle -->
  <Tooltip v-show="isHovered">
    Contextual information
  </Tooltip>

  <!-- Accordion menu with frequent toggle -->
  <div v-show="isExpanded" class="accordion-content">
    {{ content }}
  </div>
</template>

24. Wie optimiert man Listen mit v-for?

Die Optimierung von Listen ist entscheidend für die Performance bei vielen Elementen.

javascript
// Always use :key with a unique stable identifier
<template>
  <!--Unique and stable key -->
  <li v-for="item in items" :key="item.id">
    {{ item.name }}
  </li>

  <!--Index as key (reordering issues) -->
  <li v-for="(item, index) in items" :key="index">
    {{ item.name }}
  </li>
</template>

// Filtering and sorting: use computed
<script setup>
import { computed } from 'vue'

const sortedAndFilteredItems = computed(() => {
  return items.value
    .filter(item => item.isActive)
    .sort((a, b) => a.name.localeCompare(b.name))
})
</script>

// Virtualization for very long lists
<script setup>
import { useVirtualList } from '@vueuse/core'

const { list, containerProps, wrapperProps } = useVirtualList(
  largeList,
  { itemHeight: 50 }
)
</script>

<template>
  <div v-bind="containerProps" style="height: 400px; overflow: auto">
    <div v-bind="wrapperProps">
      <div v-for="item in list" :key="item.data.id">
        {{ item.data.name }}
      </div>
    </div>
  </div>
</template>

25. Erkläre das Renderless-Component-Pattern

Renderless Components kapseln Logik, ohne eine HTML-Struktur vorzugeben.

components/MouseTracker.vuejavascript
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'

const x = ref(0)
const y = ref(0)

const updatePosition = (event) => {
  x.value = event.clientX
  y.value = event.clientY
}

onMounted(() => {
  window.addEventListener('mousemove', updatePosition)
})

onUnmounted(() => {
  window.removeEventListener('mousemove', updatePosition)
})

// Expose state via slot
defineExpose({ x, y })
</script>

<template>
  <!-- Slot with props: parent decides the rendering -->
  <slot :x="x" :y="y" />
</template>
javascript
// Usage: full control over rendering
<template>
  <MouseTracker v-slot="{ x, y }">
    <div class="cursor-display">
      Position: {{ x }}, {{ y }}
    </div>
  </MouseTracker>

  <MouseTracker v-slot="{ x, y }">
    <svg>
      <circle :cx="x" :cy="y" r="10" fill="red" />
    </svg>
  </MouseTracker>
</template>

Dieses Muster trennt Logik vollständig von der Darstellung und maximiert die Wiederverwendbarkeit.

Fazit

Diese 25 Fragen decken die wichtigsten Konzepte ab, die in Vue.js-Interviews bewertet werden:

  • Reaktivität: ref, reactive, computed, watch
  • Composition API: Composables, script setup, TypeScript
  • Performance: Lazy Loading, Virtualisierung, Optimierungen
  • Vue Router: Guards, Props, Navigation
  • Pinia: Stores, Persistenz, asynchrone Actions
  • Best Practices: Struktur, Konventionen, fortgeschrittene Patterns

Eine wirkungsvolle Vorbereitung verbindet theoretisches Verständnis mit praktischer Übung am Code. Jedes hier behandelte Konzept kann im Interview Anlass für vertiefende Folgefragen sein.

Fang an zu üben!

Teste dein Wissen mit unseren Interview-Simulatoren und technischen Tests.

Tags

#vue.js
#interview
#frontend
#javascript
#technical questions

Teilen

Verwandte Artikel