Vue.js is an easy to use web app framework that we can use to develop interactive front end apps.
In this article, we’ll look at how to manipulate the DOM with Vue.js directives.
Basics
Vue lets us register or own custom directives, in addition to using built-in ones like v-for
and v-if
.
It’s useful for low-level DOM manipulation that can’t easily be done with components.
For example, we can make one as follows:
src/index.js
:
Vue.directive("focus", {
inserted(el) {
el.focus();
}
});
const vm = new Vue({
el: "#app"
});
index.html
:
<!DOCTYPE html>
<html>
<head>
<title>App</title>
<meta charset="UTF-8" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<input v-focus />
</div>
<script src="src/index.js"></script>
</body>
</html>
In the code above, we defined the focus
directive, which is referenced by adding a v-
prefix to it.
The focus
directive calls focus
on the DOM element when it’s inserted into the DOM. The inserted
method is a hook that handles the situation when the element that has the directive applied is inserted into the DOM.
The el
parameter has the DOM element, which is why we can call the focus
method on it.
Therefore, when we load the page, we’ll see that the input
element is focused. This is the work of the focus
directive.
The code above registered the directive globally. We can also register the directive locally as follows:
src/index.js
:
const focus = {
inserted(el) {
el.focus();
}
};
const vm = new Vue({
el: "#app",
directives: {
focus
}
});
index.html
:
<!DOCTYPE html>
<html>
<head>
<title>App</title>
<meta charset="UTF-8" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<input v-focus />
</div>
<script src="src/index.js"></script>
</body>
</html>
The focus
directive will then only be available to the component that it’s registered in.
Hook Functions
A directive can have the following hook functions. They’re all optional.
bind
— called only once when the directive is first bound to the element. It’s used for one-time setup workinserted
— called when the bound element is inserted into its parent node. It guarantees the parent node presence.updarted
— calls after the containing component VNode has updated but possibly before children have updated. VNode is a node in the virtual DOM, it stands for virtual node.componentUpdated
— called when the containing component’s VNode and VNodes of its children are updatedunbind
— called only once when the directive is unbound from the element
Directive Hook Arguments
The hooks above take the following arguments:
el
The element the directive is bound to. It can used to manipulate the DOM
binding
An object containing the following properties:
name
— name of the directive without thev-
prefixvalue
— value passed to the directive. For example, if we havev-foo='1'
then the value is1
.oldValue
— the previous value. This is only available inupdate
andcompoentUpdated
. It’s available whether or not the value has changed.expression
— the expression of the binding as a string. For example, if we havev-foo='1 + 2'
then it’s1 + 2
.arg
—the argument passed into the directive. For example, if we havev-foo:bar
then thearg
is‘bar‘
.modifiers
— an object with modifiers. If we havev-foo.bar.baz
then it would be{ bae: true, baz: true }
.
Everything other than el
are read-only.
For example, we can display the data that are passed from the parameters as follows:
src/index.js
:
const foo = {
inserted(el, binding, vnode) {
const stringify = JSON.stringify;
el.innerHTML = `
name:
${stringify(binding.name)}
<br>
value:
${stringify(binding.value)}
<br>
expression:
${stringify(binding.expression)}
<br>
argument
${stringify(binding.arg)}
<br>
modifiers:
${stringify(binding.modifiers)}
<br>
vnode keys:
${Object.keys(vnode).join(", ")}`;
}
};
const vm = new Vue({
el: "#app",
directives: {
foo
}
});
index.html
:
<!DOCTYPE html>
<html>
<head>
<title>App</title>
<meta charset="UTF-8" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<div v-foo:bar.baz="1 + 2"></div>
</div>
<script src="src/index.js"></script>
</body>
</html>
Then we get:
name: "foo"
value: 3
expression: "1 + 2"
argument "bar"
modifiers: {"baz":true}
vnode keys: tag, data, children, text, elm, ns, context, fnContext, fnOptions, fnScopeId, key, componentOptions, componentInstance, parent, raw, isStatic, isRootInsert, isComment, isCloned, isOnce, asyncFactory, asyncMeta, isAsyncPlaceholder
Conclusion
We can define our own Vue directives to manipulate DOM elements by binding them to specific DOM elements and then run the elements’ methods.
It works by running hooks when certain during certain stages of virtual node manipulation by Vue.
The hooks take the DOM element object as the first argument and a binding
object which has the data about the directive like name, the value passed in, modifiers and arguments.