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 (structure) - A
<script lang="ts" setup>block for TypeScript logic (functionality) - A
<style scoped>block for CSS styling (appearance)
<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”Reactive state lets the script detect when a variable changes and update the HTML accordingly.
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”Create an element/do something for each element in a list.
<!-- Create an AutonWaypointItem for each waypoint in waypoints, and add thecorresponding attributes for each one --><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 (Document Object Model) event:
<!-- handleClick() would be defined in <script>, and runs when button clicked --><button @click="handleClick">Click me</button>
<!-- Runs submitForm() when user presses "enter" in this textbox --><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('')
// Prints the new "query" value whenever it changeswatch(query, (newVal) => { console.log('Query changed:', newVal)})Lifecycle Hooks
Section titled “Lifecycle Hooks”Run some code when the Vue component enters a new phase of it’s lifecycle.
import { onMounted, onBeforeUnmount } from 'vue'
onMounted(() => { document.addEventListener('keydown', handleKey)})
onBeforeUnmount(() => { document.removeEventListener('keydown', handleKey)})Common hooks:
onMounted()- after component is added to the DOM/pageonBeforeUnmount()- 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:
<template> <GamepadDisplay :axes="axes" :buttons="buttons" /> <IndicatorDot :is-active="connected" /></template>
<script lang="ts" setup>import GamepadDisplay from './GamepadDisplay.vue'import IndicatorDot from './IndicatorDot.vue'</script>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 (useXStore).