Vue Introduction
Vue Introduction
Section titled “Vue Introduction”Vue is a versatile and beginner-friendly JavaScript framework. This introduction covers what is relevant to our codebase.
We use the Composition API with <script setup>, which is the modern recommended style for Vue 3.
File Structure
Section titled “File Structure”A typical .vue file includes:
- A
<template>block for HTML markup - A
<script setup>block for TypeScript logic - A
<style scoped>block for CSS styling
<template> <div class="flex flex-col gap-2"> <!-- Child content here --> </div></template>
<script lang="ts" setup>import { ref } from 'vue'
const count = ref(0)</script>
<style scoped>/* Component-specific styles */</style>Reactive State: ref and reactive
Section titled “Reactive State: ref and reactive”Use ref() for primitive values and reactive() for objects:
import { ref, reactive } from 'vue'
const count = ref(0)const user = reactive({ name: 'Alice', age: 20 })
count.value++ // access .value in scriptuser.name = 'Bob' // direct access for reactiveIn <template>, refs are auto-unwrapped (no .value needed):
<p>{{ count }}</p>Looping Through Data: v-for
Section titled “Looping Through Data: v-for”<AutonWaypointItem v-for="(waypoint, index) in waypoints" :key="waypoint.id" :waypoint="waypoint" :index="index" @delete="removeWaypoint(index)"/>Conditional Rendering: v-if
Section titled “Conditional Rendering: v-if”Only render the element if the condition is true.
<button v-if="!enabled" class="cmd-btn cmd-btn-danger" @click="toggle"> Disabled</button>
<button v-else class="cmd-btn cmd-btn-success" @click="toggle"> Enabled</button>Event Binding: @
Section titled “Event Binding: @”Bind a function to a DOM event:
<button @click="handleClick">Click me</button><input @keydown.enter="submitForm" />Computed Properties
Section titled “Computed Properties”Derived values that automatically update when their dependencies change:
import { ref, computed } from 'vue'
const items = ref([1, 2, 3])const total = computed(() => items.value.reduce((a, b) => a + b, 0))Watchers
Section titled “Watchers”Run side effects when a reactive value changes:
import { ref, watch } from 'vue'
const query = ref('')
watch(query, (newVal) => { console.log('Query changed:', newVal)})Lifecycle Hooks
Section titled “Lifecycle Hooks”import { onMounted, onBeforeUnmount } from 'vue'
onMounted(() => { document.addEventListener('keydown', handleKey)})
onBeforeUnmount(() => { document.removeEventListener('keydown', handleKey)})Common hooks:
onMounted()- after component is added to the DOMonBeforeUnmount()- before component is removed, for cleanuponUpdated()- after any DOM update
Importing Components
Section titled “Importing Components”With <script setup>, imported components are automatically available in the template without registration:
<script lang="ts" setup>import GamepadDisplay from './GamepadDisplay.vue'import IndicatorDot from './IndicatorDot.vue'</script>
<template> <GamepadDisplay :axes="axes" :buttons="buttons" /> <IndicatorDot :is-active="connected" /></template>State Management: Pinia
Section titled “State Management: Pinia”We use Pinia (not Vuex) for shared state across components:
import { useWebsocketStore } from '@/stores/websocket'
const websocketStore = useWebsocketStore()websocketStore.sendMessage('arm', { type: 'ra_controller', axes, buttons })Pinia stores are defined in src/stores/ and accessed via composable functions (useXxxStore).