Introduction to the Vue Instance
Every Vue application starts with creating a Vue instance - the heart of a Vue application.
In Vue 3, we create this instance using the createApp() function, which serves as the entry
point and connects the application to a DOM element.
// Vue 3 App Creation
const app = Vue.createApp({
// root component options
})
// Mount the app to a DOM element
app.mount('#app')
This creates a connection between your Vue code and the HTML element with id="app",
establishing the boundary of your Vue application. Everything inside this element becomes reactive and
managed by Vue.
Real-world analogy: Think of the Vue instance as the brain of your application. Just as the brain coordinates all body systems, the Vue instance orchestrates all components, directives, and reactivity of your application.
Vue 2 vs Vue 3 App Creation
If you encounter Vue 2 code, you'll notice a different syntax for creating instances:
Vue 2 (older)
// Creating a Vue instance in Vue 2
new Vue({
// options here
}).$mount('#app')
Vue 3 (current)
// Creating a Vue app in Vue 3
Vue.createApp({
// options here
}).mount('#app')
Vue 3's approach provides better separation of concerns and more flexibility for advanced use cases, particularly in larger applications with plugins, custom components, and global configurations.
App Configuration and the Root Component
When creating a Vue application, we pass a configuration object to createApp() - this object
defines the root component of our application. The object contains various properties:
Core Options in the Root Component
- data(): A function that returns an object containing all reactive data properties used by the component
- methods: Functions that can be called from the component's template
- computed: Derived properties that cache their results based on reactive dependencies
- watch: Special functions that react to changes in specific data properties
- Lifecycle hooks: Methods that run at specific points in a component's lifecycle
Vue.createApp({
// Reactive state data
data() {
return {
count: 0,
message: 'Hello Vue!'
}
},
// Methods that can be called from templates
methods: {
increment() {
this.count++
}
},
// Derived data properties
computed: {
doubleCount() {
return this.count * 2
}
},
// Watch for changes and react
watch: {
count(newValue, oldValue) {
console.log(`Count changed from ${oldValue} to ${newValue}`)
}
},
// Lifecycle hook - when component is mounted to DOM
mounted() {
console.log('Application loaded and mounted!')
}
}).mount('#app')
Vue Directives Overview
Directives are special attributes in Vue templates that apply reactive behavior to the
rendered DOM. They are recognizable by the v- prefix and are one of Vue's most powerful features.
Real-world analogy: Directives are like "smart instructions" attached to elements in your HTML. If regular HTML attributes are like static signs (e.g., "EXIT" signs that never change), directives are like digital signs that can change their displayed information based on conditions or events.
Core Vue Directives
Vue provides several built-in directives, each with a specific purpose:
v-text and Mustache Syntax
The most basic form of data binding in Vue is text interpolation using mustache syntax or the v-text directive:
<!-- Using mustache syntax (preferred for text) -->
<p>{{ message }}</p>
<!-- Equivalent using v-text directive -->
<p v-text="message"></p>
Real-world use case: Displaying dynamic user information like names, account balances, or product details that come from your application data.
v-html
For rendering HTML content rather than plain text:
<div v-html="rawHtml"></div>
Security Warning: Never use v-html with user-provided content as it
can lead to XSS vulnerabilities. Only use it with trusted content.
Real-world use case: Rendering formatted content from a CMS where the HTML has been sanitized server-side, like a blog post with formatting.
v-bind
Used to dynamically bind attributes to an element based on your data:
<!-- Full syntax -->
<img v-bind:src="imageUrl" v-bind:alt="imageDescription">
<!-- Shorthand (preferred) -->
<img :src="imageUrl" :alt="imageDescription">
Real-world use case: Dynamically changing an image source, toggling CSS classes, or updating a link URL based on application state.
v-on
Used to listen to DOM events and trigger JavaScript when they're triggered:
<!-- Full syntax -->
<button v-on:click="increment">Increment</button>
<!-- Shorthand (preferred) -->
<button @click="increment">Increment</button>
<!-- With inline handler -->
<button @click="count++">Increment</button>
Real-world use case: Handling form submissions, button clicks, user interactions, or responding to custom events from child components.
Conditional & List Rendering Directives
v-if, v-else-if, v-else
These directives conditionally render elements based on the truthiness of an expression:
<div v-if="type === 'A'">Type A</div>
<div v-else-if="type === 'B'">Type B</div>
<div v-else>Not A or B</div>
Real-world use case: Showing different UI components based on user roles, toggle between views, or displaying error messages conditionally.
v-show
Similar to v-if but toggles the element's CSS display property instead of
adding/removing it from the DOM:
<div v-show="isVisible">This toggles visibility using CSS display</div>
When to use v-show vs v-if:
- Use
v-ifwhen the condition changes infrequently, or when content should not be rendered at all until needed - Use
v-showwhen you need to toggle something very frequently, as it's cheaper to toggle visibility than to create/destroy elements
v-for
Used to render lists of items based on an array:
<!-- Basic array iteration -->
<ul>
<li v-for="item in items" :key="item.id">
{{ item.name }}
</li>
</ul>
<!-- With index -->
<ul>
<li v-for="(item, index) in items" :key="item.id">
{{ index }}: {{ item.name }}
</li>
</ul>
<!-- Object properties iteration -->
<ul>
<li v-for="(value, key) in object" :key="key">
{{ key }}: {{ value }}
</li>
</ul>
Important: Always use the :key directive with v-for to give
Vue a way to track each node's identity, making DOM updates more efficient.
Real-world use case: Rendering lists of products, user comments, to-do items, or table rows from your application data.
Two-Way Binding: v-model
The v-model directive creates two-way data binding between form inputs and the application state,
combining v-bind and v-on in a single directive:
<!-- Basic text input -->
<input v-model="message">
<p>Message: {{ message }}</p>
<!-- Checkbox -->
<input type="checkbox" v-model="checked">
<p>Checked: {{ checked }}</p>
<!-- Radio buttons -->
<input type="radio" v-model="picked" value="One">
<input type="radio" v-model="picked" value="Two">
<p>Picked: {{ picked }}</p>
<!-- Select dropdown -->
<select v-model="selected">
<option value="">Please select one</option>
<option value="A">Option A</option>
<option value="B">Option B</option>
</select>
<p>Selected: {{ selected }}</p>
Under the hood: v-model is essentially a shorthand for:
Real-world use case: Building forms for user input, search interfaces, filtering controls, or any UI that requires collecting user input.
v-model Modifiers
Vue provides special modifiers for v-model to handle common form input transformations:
<!-- Trim whitespace from input -->
<input v-model.trim="message">
<!-- Cast input value to number -->
<input v-model.number="age" type="number">
<!-- Only update after change event, not on every input -->
<input v-model.lazy="message">
Special Directives
v-once
Renders the element and component only once, then becomes static content:
<span v-once>This will never change: {{ msg }}</span>
Real-world use case: Optimizing performance for content that won't change, like fixed headings or static configuration values.
v-pre
Skips compilation for this element and all its children:
<span v-pre>{{ This will be displayed as-is }}</span>
Real-world use case: Displaying raw mustache syntax or temporarily disabling compilation for a section during debugging.
v-cloak
Used to hide un-compiled mustache bindings until the Vue instance is ready:
<!-- In your CSS -->
[v-cloak] {
display: none;
}
<!-- In your HTML -->
<div v-cloak>
{{ message }}
</div>
Real-world use case: Preventing "template flashing" in applications where there might be a noticeable delay before the Vue application loads completely.
Custom Directives
Vue allows creating custom directives for specialized DOM manipulations:
// Define a global custom directive
const app = Vue.createApp({})
// Register a global custom directive 'v-focus'
app.directive('focus', {
// When the bound element is mounted into the DOM
mounted(el) {
// Focus the element
el.focus()
}
})
// Usage in template
<input v-focus>
Directive Hook Functions: Custom directives can implement various hooks:
beforeMount: Called before the element is inserted into the DOMmounted: Called when the element is inserted into the DOMbeforeUpdate: Called before the containing component updatesupdated: Called after the containing component has updatedbeforeUnmount: Called before the element is removed from the DOMunmounted: Called when the element is removed from the DOM
Real-world use case: Creating reusable behaviors like auto-focusing inputs, implementing scroll or lazy-loading behaviors, or handling custom tooltips.
Complete Instance Example
Let's put it all together with a practical example of a Vue instance using various directives:
<!DOCTYPE html>
<html>
<head>
<title>Vue Instance & Directives Demo</title>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<style>
.completed { text-decoration: line-through; color: gray; }
[v-cloak] { display: none; }
</style>
</head>
<body>
<div id="app" v-cloak>
<h1>{{ title }}</h1>
<!-- Input with v-model -->
<input v-model.trim="newTask" placeholder="Add a task" @keyup.enter="addTask">
<button @click="addTask" :disabled="!newTask">Add</button>
<!-- Conditional rendering -->
<p v-if="tasks.length === 0">No tasks yet. Add one!</p>
<!-- List rendering with multiple directives -->
<ul v-else>
<li v-for="(task, index) in tasks" :key="task.id"
:class="{ completed: task.completed }">
<input type="checkbox" v-model="task.completed">
<span v-if="!task.editing">{{ task.text }}</span>
<input v-else v-model="task.text" @blur="task.editing = false" v-focus>
<!-- Event handling -->
<button @click="task.editing = !task.editing">Edit</button>
<button @click="removeTask(index)">Delete</button>
</li>
</ul>
<!-- Computed property usage -->
<p>Remaining: {{ remainingTasks }}</p>
</div>
<script>
// Register a custom focus directive
const app = Vue.createApp({
data() {
return {
title: 'Task Manager',
newTask: '',
tasks: [
{ id: 1, text: 'Learn Vue Basics', completed: false, editing: false },
{ id: 2, text: 'Build a Todo App', completed: false, editing: false }
],
nextId: 3
}
},
computed: {
remainingTasks() {
return this.tasks.filter(task => !task.completed).length
}
},
methods: {
addTask() {
if (this.newTask.trim()) {
this.tasks.push({
id: this.nextId++,
text: this.newTask,
completed: false,
editing: false
})
this.newTask = ''
}
},
removeTask(index) {
this.tasks.splice(index, 1)
}
}
})
// Register a custom directive
app.directive('focus', {
mounted(el) {
el.focus()
}
})
// Mount the app
app.mount('#app')
</script>
</body>
</html>
This example demonstrates:
- Creating and mounting a Vue instance
- Using data properties, computed properties, and methods
- Applying multiple directives (
v-model,v-if/v-else,v-for,v-bind,v-on) - Creating and using a custom directive
- Event handling with modifiers
- Class binding for dynamic styling
Activities for Practice
Exercise 1: Interactive Name Badge
Create a simple Vue application that displays a name badge. Include:
- An input field where users can type their name (use
v-model) - A color picker for the badge background (use
v-modelwith a select dropdown) - A live preview of the badge showing the entered name and selected color (use
v-bindfor styling) - A button to toggle the badge visibility (use
v-showorv-if)
Exercise 2: Shopping List Builder
Create a shopping list application that allows users to:
- Add items to a list (use
v-modelandv-on) - Display the list of items (
v-forwith:key) - Mark items as purchased (use
v-bindfor styling andv-modelwith checkboxes) - Delete items from the list (
v-onwith click event) - Show a message when the list is empty (
v-if/v-else)
Exercise 3: Custom Directive Creation
Create a Vue application with a custom directive. For example:
- Create a
v-highlightdirective that changes the background color of an element when hovered - Create a
v-format-currencydirective that formats a number as currency - Create a
v-autoresizedirective for textareas that automatically resizes based on content
Apply your custom directive to appropriate elements in a simple Vue application.