These chapters are where the modifiers live: the v-on modifiers, the key and system modifiers, the v-model modifiers, the watcher options. They are exactly the kind of fact an interviewer can check in five seconds, and exactly the kind that fades if you have used a UI library for two years.
v-if / v-else-if / v-else on adjacent elements; <template v-if> groups elements without a wrapper. v-show toggles display and keeps the element; it does not work on <template> and has no v-else. v-if is lazy and has higher toggle cost; v-show has higher initial cost and cheap toggles.v-if with v-for on the same element is not recommended; in Vue 3 v-if is evaluated first and cannot see the loop variable. Move v-if to a wrapping <template v-for>.v-for: (item, index) in items, of works like in, objects iterate as (value, key, index) in Object.values order, and a range n in 10 starts at 1. <template v-for> renders multiple elements per item.key should be a string or number, never an object; without a key Vue patches in place, which is efficient only when the list output does not depend on child component state or temporary DOM state.push, pop, shift, unshift, splice, sort, reverse) trigger updates; non-mutating methods (filter, concat, slice) return a new array that you assign. reverse() and sort() mutate: copy before using them in a computed.v-for where a computed is not feasible, use a method.v-for do not receive item automatically; pass props explicitly.@click="count++") and method handlers (@click="greet", which receives the native event). Call methods inline with arguments and pass $event or an arrow function for the event..stop, .prevent, .self, .capture, .once, .passive. Order matters (@click.prevent.self vs @click.self.prevent); do not combine .passive with .prevent..enter, .tab, .delete (Delete and Backspace), .esc, .space, .up, .down, .left, .right, plus any kebab-cased KeyboardEvent.key (.page-down). System modifiers: .ctrl, .alt, .shift, .meta; .exact requires exactly those. Mouse: .left, .right, .middle.@click="one($event), two($event)".v-model on <input>, <textarea>, <select>, checkboxes and radios; it ignores the initial value, checked and selected attributes and uses the bound state as the source of truth. Interpolation inside <textarea> does not work; use v-model.v-model; true-value/false-value customise the values (not submitted with the form). Radio: the bound value. Select: single value or array with multiple; add a disabled empty option as placeholder to avoid the iOS first-option bug. Options can be rendered with v-for and bound to objects with :value..lazy (sync on change instead of input), .number (cast with parseFloat, kept as string if it fails; automatic for type="number"), .trim.v-model does not update during composition; bind :value and @input if you need it to.watch(obj.count, …) passes a number); use a getter.deep: true (traverses; expensive), deep: number (3.5+, depth limit), immediate: true, once: true (3.4+), flush: 'pre' | 'post' | 'sync'.watchEffect runs immediately and tracks whatever it reads synchronously before the first await; use watch when you need old values, laziness or control over which dependencies trigger.onWatcherCleanup() (3.5+, must be called synchronously during the callback) or the onCleanup argument passed to the callback.pre); watchPostEffect/flush: 'post' run after the DOM update; watchSyncEffect/flush: 'sync' run synchronously.setup stop with the component; watchers created asynchronously must be stopped manually with the returned handle, which in 3.5 also has pause() and resume().ref attribute plus useTemplateRef('name') (3.5+) or a ref with the same name; available after mount, null when unmounted. Refs in v-for yield an array whose order is not guaranteed. Function refs receive the element. A ref on a component gives the instance; with <script setup> only defineExposed members are visible.<script setup> and use directly; props via defineProps; events via defineEmits/$emit; content via slots; dynamic components with <component :is> (string name or component object). In-DOM template caveats: case insensitivity (kebab-case names and props), no self-closing tags, and element placement restrictions (<table>) solved with is="vue:my-row".onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted, onErrorCaptured, onRenderTracked/onRenderTriggered (dev only), onActivated/onDeactivated, onServerPrefetch. Hooks must be registered synchronously during setup; a hook registered after an await is not attached to the instance.<script setup lang="ts">
const items = ref([{ id: 1, name: 'b', done: false }, { id: 2, name: 'a', done: true }])
const sorted = computed(() => [...items.value].sort((x, y) => x.name.localeCompare(y.name))) // copy before sort
const query = ref('')
const agree = ref<'yes' | 'no'>('no')
const input = useTemplateRef<HTMLInputElement>('input')
// Cannot watch items.length directly: use a getter. `once` since 3.4.
watch(() => items.value.length, n => console.log('count', n), { once: true })
watch(query, async (q, _old, onCleanup) => {
const controller = new AbortController()
onCleanup(() => controller.abort())
await $fetch('/api/search', { query: { q }, signal: controller.signal })
})
onMounted(() => input.value?.focus())
</script>
<template>
<input ref="input" v-model.trim.lazy="query" @keyup.enter.exact="query = ''" @keydown.ctrl.enter="console.log('save')">
<input v-model="agree" type="checkbox" true-value="yes" false-value="no">
<ul>
<template v-for="item in sorted" :key="item.id">
<li v-if="!item.done" @click.self.prevent="item.done = true">{{ item.name }}</li>
</template>
</ul>
<p v-show="items.length === 0">Nothing to do</p>
</template>
.passive promises the browser you will not call preventDefault(), which lets scrolling start immediately; combining it with .prevent makes the browser ignore the prevent and warn. Pick one.
.ctrl.enter.exact and test it with and without Shift held.setTimeout and confirm it keeps firing after the component unmounts; then stop it with the handle."v-model has .lazy to sync on change instead of input, .number to cast with parseFloat, which is automatic on number inputs, and .trim. v-on has event modifiers .stop, .prevent, .self, .capture, .once and .passive, applied in the order written; key modifiers such as .enter, .esc, .tab, .delete and any kebab-cased key name; system modifiers .ctrl, .alt, .shift, .meta with .exact to require that exact combination; and mouse modifiers .left, .right, .middle. The one combination to avoid is .passive with .prevent."
Nothing yet. Notes filed here show up on this page and the section overview.
Essentials I — templates and reactivity
Creating an Application, Template Syntax, Reactivity Fundamentals, Computed Properties, and Class and Style Bindings, distilled to the facts and caveats the guide states.
Components I — registration, props, events, v-model
Component registration, props declaration and validation including Boolean casting and reactive destructure, event declaration and validation, and component v-model with defineModel.