This stack overflow question is the # 1 result for Google’s query “vue directive vs component”. Saurshazs answer is currently accepted and this is very wrong in Vue 2.0. I suppose this leads many people astray, so I will weigh it here.
The answer to "should I use a directive or component in Vue" is almost always a component.
Do you want to have reusable HTML? That is reusable widgets? Then use the component. Do you want two of these widgets to have discrete data? Then use the component. The data of one will NOT override the data of the other. Perhaps this was true in Vue 1.0, I do not know. But this is not at all true in Vue 2.0. In Vue 2.0, your components have a data function that returns a unique dataset. View this reality in the Vue drop-down list, which has HTML markup similar to the UI Bootstrap dropdown menu:
<template> <span class="dropdown sm-dropdown" @click="toggle" :class="{'open': isOpen}"> <a class="dropdown-toggle"> <span class="special-field">{{ label }}</span> </a> <ul class="dropdown-menu"> <li v-for="choice in choices"> <a @click.prevent="click(choice)">{{ choice.label }}</a> </li> </ul> </span> </template> <script> export default { name: 'Dropdown', props: ['label', 'options', 'onChange'], data() { return { choices: this.options, isOpen: false } }, methods: { click(option) { this.onChange(option); }, toggle() { this.isOpen = !this.isOpen; } } } </script>
Now in the parent component I can do something like this:
<template> <div class="container"> <dropdown :label="-- Select --" :options="ratingChoices" :onChange="toggleChoice" > </dropdown> <dropdown :label="-- Select --" :options="ratingChoices" :onChange="toggleChoice" > </dropdown> </div> </template> <script> import Dropdown from '../dropdown/dropdown.component.vue'; export default { name: 'main-directive', components: { Dropdown }, methods: { toggleChoice(newChoice) { </script>
There is a decent amount of code here. What happens, we configure the parent component and inside this parent component we have two drop-down lists. In other words, the dropdown component is called twice. The point I am trying to make when displaying this code is this: when I click on the isOpen drop-down menu for this, the dropdown changes for this directive and only for this directive. Clicking on one of the drop-down menus does not affect the other drop-down menu.
Do not choose between components or directives based on whether you want discrete data. Components allow discrete data.
So, when do you want to select a directive in Vue?
Here are some suggestions that I hope will make you think in the right direction.
- You want to choose a directive when you want to extend the functionality of HTML components, and you suspect that you will need this extensibility for several components, and you do not want your DOM to become deeper as a result. To understand what I mean, let's look at the directives that Vue provides out of the box. Take, for example, its
v-for directive. This allows you to iterate through the collection. This is very useful, and you need to be able to do this in any component that you need, and you do not want the DOM to go deeper. This is a good example where a directive is the best choice. [one] - You want to select a directive if you want a single HTML tag to have multiple functions. For example, an element that launches an Ajax request and has its own tooltip. Assuming you need tooltips for items other than Ajax startup items, it makes sense to break them into two different things. In this example, I would make a hint with a directive and an Ajax function controlled by a component, so I could use the built-in
@click directive available in components.
1 Footnote for the more curious. Theoretically, v-for could be done as a component, but it would require a deeper than necessary DOM every time you wanted to use v-for , as well as a more inconvenient syntax. If Vue chooses a component for this, instead:
<a v-for="link in links" :href="link.href">link.anchor</a>
The syntax should have been as follows:
<v-for items="link in links"> <a :href="link.href">link.anchor</a> </v-for>
This is not only inconvenient, but since the component code was needed to implement the <slot></slot> syntax to get innerHTML, and since slots cannot be immediate children of a <template> declaration (since there is no guarantee that the slot layout has a single input node at its upper level), this means that the surrounding top-level element must be present in the component definition for v-for . Consequently, the DOM will become deeper than necessary. The directive was clearly the right choice here.