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 inupdateandcompoentUpdated. 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:barthen theargis‘bar‘.modifiers— an object with modifiers. If we havev-foo.bar.bazthen 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.