Vue.js v-on Directive
Introduction
The v-on
directive is one of the most important features in Vue.js, allowing you to listen to DOM events and execute JavaScript when those events are triggered. Often abbreviated with the @
symbol, this directive enables you to create interactive web applications by responding to user actions like clicks, key presses, form submissions, and more.
In this guide, we'll explore the v-on
directive in detail, including its syntax, usage patterns, modifiers, and practical applications.
Basic Syntax and Usage
The basic syntax of the v-on
directive is:
<element v-on:event="handler"></element>
Or using the shorthand syntax:
<element @event="handler"></element>
Where:
event
is the DOM event you want to listen for (likeclick
,submit
,keyup
)handler
is either a method defined in your Vue component or an inline JavaScript statement
Simple Event Handling
Click Events
Let's start with a simple button click example:
<template>
<div>
<p>Count: {{ count }}</p>
<button v-on:click="increment">Increment</button>
<!-- Shorthand syntax -->
<button @click="decrement">Decrement</button>
</div>
</template>
<script>
export default {
data() {
return {
count: 0
}
},
methods: {
increment() {
this.count += 1
},
decrement() {
if (this.count > 0) {
this.count -= 1
}
}
}
}
</script>
In this example:
- We've defined a
count
data property - Created two methods,
increment
anddecrement
- Attached these methods to button click events using both the full syntax (
v-on:click
) and shorthand (@click
)
Event Handlers with Arguments
You can pass arguments to your event handlers:
<template>
<div>
<p>Current value: {{ value }}</p>
<button @click="updateValue(5)">Add 5</button>
<button @click="updateValue(10)">Add 10</button>
</div>
</template>
<script>
export default {
data() {
return {
value: 0
}
},
methods: {
updateValue(amount) {
this.value += amount
}
}
}
</script>
Accessing the Event Object
Sometimes you need access to the original DOM event. Vue automatically passes it as the first parameter if you don't provide arguments:
<template>
<div>
<input @keyup="onKeyUp" placeholder="Type something...">
<p>You pressed: {{ lastKey }}</p>
</div>
</template>
<script>
export default {
data() {
return {
lastKey: ''
}
},
methods: {
onKeyUp(event) {
this.lastKey = event.key
}
}
}
</script>
If you need the event object along with custom arguments, you can use the special $event
variable:
<button @click="handleClick('button-clicked', $event)">Click me</button>
<script>
export default {
methods: {
handleClick(message, event) {
console.log(message)
console.log('Event target:', event.target)
}
}
}
</script>
Inline Handlers
For simple operations, you can use inline JavaScript:
<template>
<div>
<p>Count: {{ count }}</p>
<button @click="count++">Increment</button>
<button @click="count = 0">Reset</button>
</div>
</template>
<script>
export default {
data() {
return {
count: 0
}
}
}
</script>
Event Modifiers
Vue provides event modifiers to handle common tasks without explicitly writing them in event handlers. You add modifiers by appending them to the event with a dot.
<template>
<div>
<!-- Stop propagation -->
<button @click.stop="handleClick">Stop Propagation</button>
<!-- Prevent default -->
<form @submit.prevent="submitForm">
<button type="submit">Submit</button>
</form>
<!-- Chain modifiers -->
<a @click.stop.prevent="handleLink">Link with modifiers</a>
<!-- Only trigger once -->
<button @click.once="showMessage">Show Message Once</button>
<!-- Capture mode -->
<div @click.capture="handleCapture">
Capture Phase
</div>
<!-- Self modifier (only trigger if event.target is the element itself) -->
<div @click.self="handleSelf">
Only trigger for clicks on this div, not children
</div>
</div>
</template>
Key and Mouse Modifiers
Vue provides modifiers for keyboard and mouse events:
Key Modifiers
<template>
<div>
<!-- Only trigger when Enter key is pressed -->
<input @keyup.enter="submitForm">
<!-- Common key aliases: enter, tab, delete, esc, space, up, down, left, right -->
<input @keyup.esc="clearInput">
<!-- Key combinations -->
<input @keyup.alt.enter="specialSubmit">
</div>
</template>
Mouse Button Modifiers
<template>
<div>
<!-- Only trigger for left, right, or middle mouse button -->
<button @click.left="leftClick">Left Click</button>
<button @click.right="rightClick">Right Click</button>
<button @click.middle="middleClick">Middle Click</button>
</div>
</template>
System Modifier Keys
You can use the following modifiers to trigger mouse or keyboard event listeners only when the corresponding modifier key is pressed:
<template>
<div>
<!-- Ctrl, Alt, Shift, Meta -->
<button @click.ctrl="doSomething">Ctrl + Click</button>
<button @click.alt="doSomethingElse">Alt + Click</button>
<div @keyup.shift.enter="handleShiftEnter">Press Shift+Enter</div>
<!-- Meta key (Windows key or Command key) -->
<div @click.meta="handleMetaClick">Meta + Click</div>
<!-- Exact modifier - triggers only if ONLY specified keys are pressed -->
<button @click.ctrl.exact="onCtrlClick">Ctrl only (no other keys)</button>
</div>
</template>
Practical Examples
Form Handling
<template>
<form @submit.prevent="submitForm">
<div>
<label for="name">Name:</label>
<input
id="name"
v-model="form.name"
@focus="clearError('name')"
/>
<p v-if="errors.name" class="error">{{ errors.name }}</p>
</div>
<div>
<label for="email">Email:</label>
<input
id="email"
type="email"
v-model="form.email"
@blur="validateEmail"
/>
<p v-if="errors.email" class="error">{{ errors.email }}</p>
</div>
<button type="submit" :disabled="isSubmitting">
{{ isSubmitting ? 'Submitting...' : 'Submit' }}
</button>
</form>
</template>
<script>
export default {
data() {
return {
form: {
name: '',
email: ''
},
errors: {
name: '',
email: ''
},
isSubmitting: false
}
},
methods: {
clearError(field) {
this.errors[field] = ''
},
validateEmail() {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
if (!emailRegex.test(this.form.email)) {
this.errors.email = 'Please enter a valid email address'
} else {
this.errors.email = ''
}
},
submitForm() {
// Validate form
if (!this.form.name) {
this.errors.name = 'Name is required'
}
this.validateEmail()
// Check for errors
if (this.errors.name || this.errors.email) {
return
}
// Submit form
this.isSubmitting = true
// Simulate API call
setTimeout(() => {
alert(`Form submitted!\nName: ${this.form.name}\nEmail: ${this.form.email}`)
this.isSubmitting = false
// Reset form
this.form.name = ''
this.form.email = ''
}, 1500)
}
}
}
</script>
Interactive List Management
<template>
<div>
<h2>Task List</h2>
<div>
<input
v-model="newTask"
@keyup.enter="addTask"
placeholder="Add a new task"
/>
<button @click="addTask">Add</button>
</div>
<ul>
<li v-for="(task, index) in tasks" :key="index">
<input
type="checkbox"
:checked="task.completed"
@change="toggleTask(index)"
/>
<span :class="{ completed: task.completed }">
{{ task.text }}
</span>
<button @click.stop="deleteTask(index)">Delete</button>
</li>
</ul>
<div class="controls">
<button @click="clearCompleted">Clear Completed</button>
<button @click="markAllCompleted">Mark All Completed</button>
</div>
</div>
</template>
<script>
export default {
data() {
return {
newTask: '',
tasks: [
{ text: 'Learn Vue.js', completed: false },
{ text: 'Build a project', completed: false },
{ text: 'Share with friends', completed: false }
]
}
},
methods: {
addTask() {
if (this.newTask.trim()) {
this.tasks.push({
text: this.newTask,
completed: false
})
this.newTask = ''
}
},
toggleTask(index) {
this.tasks[index].completed = !this.tasks[index].completed
},
deleteTask(index) {
this.tasks.splice(index, 1)
},
clearCompleted() {
this.tasks = this.tasks.filter(task => !task.completed)
},
markAllCompleted() {
this.tasks.forEach(task => {
task.completed = true
})
}
}
}
</script>
<style scoped>
.completed {
text-decoration: line-through;
color: gray;
}
</style>
Event Flow Visualization
Understanding event flow (bubbling and capturing) is important when working with event handlers:
In Vue, you can control this flow with modifiers like .stop
, .prevent
, and .capture
.
Summary
The v-on
directive is a powerful tool in Vue.js for handling user interactions and events. Key points to remember:
- Use
v-on:event
or the shorthand@event
to listen to DOM events - You can call methods, use inline statements, or combine both approaches
- Access the event object using the implicit parameter or the
$event
variable - Event modifiers like
.stop
,.prevent
, and.once
simplify common patterns - Key and mouse modifiers allow for specific user interaction patterns
- Using the right event handling approach can make your code more maintainable
By mastering the v-on
directive, you can create highly interactive Vue applications that respond smoothly to user input.
Practice Exercises
- Create a simple counter application with buttons to increment, decrement, and reset the count.
- Build a form with validation that checks inputs on blur events and prevents submission if there are errors.
- Create a keyboard shortcut system using key modifiers that performs different actions when pressing different key combinations.
- Implement a drag-and-drop interface using mouse events.
- Create a custom event logger that captures and displays all events happening on a specific element.
Additional Resources
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)