The Complete Vue.js Event System Guide That The Official Doc Didn’t Explain In Detail — Part 1
Event Handling
Vue.js is implemented with a powerful yet easy-to-use event system that covers most of our daily development needs when it comes to user interaction. In this series, we will go through all parts of the event system in Vue that you could possibly use in your projects.
Let’s start off with Event Handling.
Introduction
Here’s a simple Vue component with a line of text and a button:
When the user clicks on the button, we want to show a dialog with a message. So we need to bind a click event onto the <button>
element. To bind an event onto an element in Vue's template, we can use Vue's v-on
directive, and the event is the built-in click
event:
Normally we will use v-on
's shortcut @
:
This means when the <button>
element is clicked, Vue will try to find a callback function (event handler) named showDialog
and execute it. We now need to define this function.
If we define a normal JavaScript function like the below:
Will it work when clicking the button?
It won’t work, and we got the error in the console:
“Property or method “showDialog” is not defined on the instance…”
This indicates the callback function must be defined on the instance, in our case here, on a VueComponent
instance (because we are within a Vue component). The place to put a function on a VueComponent
instance is the methods
option, so let's move the callback into it:
The alert dialog is now shown.
Use v-on:xxxx
or @xxxx
to bind (listen to) an event. xxxx
is the event name that can be a built-in event such as click
, or a custom event.
Passing arguments
Can the showDialog
method get arguments? Yes, actually if we add a parameter in the function definition and print it out after clicking:
We can see it is the event object (of type PointerEvent
, which is the native DOM event). Because it is the native event, we can access its target
property:
By default, Vue will pass the native DOM object as the first argument into the event callback function (event handler).
Now if we want to pass an argument to showDialog
from the template
, we can put the argument in the parenthesis after the method name. For example:
It works as expected, but we might still want to access the event object, so can we do this?
No, the output is undefined
. To solve this issue, Vue implemented a keyword $event
, and if we add it as the second argument in the template:
The method receives the event object.
$event
works like a placeholder in Vue's template. When Vue parses the template and scans the $event
, it will replace it with the DOM event object.
Can we switch the order of text
and $event
, like this?
Yes, then $event
will be passed to the 1st parameter defined in the method, and text
to the 2nd parameter.
The order of arguments in the template is the order they are passed to the parameters of the event callback.
@click="showDialog()"
works the same as @click="showDialog($event)"
, the difference is the second form allows you to access the event object and pass arguments.
`this` inside event callbacks
Now let’s look at the this
inside our event callback method by printing it out:
It points to the current component, that is, a VueComponent
instance. On this instance, we can see the event callback showDialog
defined in the methods
option. The [[TargetFunction]]
is ƒ showDialog(event, text)
, which means Vue will execute this ƒ showDialog(event, text)
function when the event is triggered. Also [[BoundThis]]
indicates the this
keyword in showDialog
is bound to the current VueComponent
instance (current component). This is automatically done by Vue, and we can verify it:
We created a data
property and save the value of this
in mounted
, which points to the current component instance. Then in the showDialog
method body, we do a comparison, and both this
and this.instance
point to the same object:
So far, we have defined showDialog
as a traditional function, what if changing it to an arrow function?
Now the this
inside showDialog
becomes undefined
, and this is because arrow functions don't have their own this
binding. Therefore, when line 15 refers to this
, it will go up and look in the outer context, which is none, so this
in line 15 gets undefined
.
All functions that are managed by Vue, e.g. methods, computed functions, watchers, etc. are better to be traditional functions. This can ensure their this
always points to the current VueComponent
instance. (The binding is done by Vue when it creates the component instance.)
All right, this concludes Part 1 of this series, see you in the next section.
Here are some more articles on Vue.js:
Vue.js Components Communication Patterns (without Vuex) — Part 1
Vue.js Components Communication Patterns (without Vuex) — Part 2
Vue.js Components Communication Patterns (without Vuex) — Part 3
Vue.js Components Communication Patterns (without Vuex) — Part 4
Vue.js Components Communication Patterns (without Vuex) — Part 5
Vue.js Components Communication Patterns (without Vuex) — Part 6
Vue.js Components Communication Patterns (without Vuex) — Part 7
Build your own Vue.js UI library based on Vuetify and publish it to NPM