Did you know that there are several ways to create Vue Components?
Here we'll discuss 4 of them.
TL;DR
I've created a CodeSandbox project to demonstrate those 4 ways.
If you'd like to self-explore, go ahead and click here.
If you want the full picture, keep reading.
The full story
For demonstration purposes, I came up with this simple task that is required from each component that we'll create:
Component Requirements
- Get a list of string items (in the props).
- Display a button for each item.
- Each button should have
lightsteelblue
background. - The text of each button should be the string of that item.
- upon clicking a button, the related item is considered selected.
- Each button should have
- Display a status string inside a
<p>
element.- at first the status should be
Please select your favorite
. - when an item is selected the status will change to reflect that selection. For example: if
Picard
is selected, the status should be:You selected Picard
(yeah, I'm a Trekkie)
- at first the status should be
I then went ahead and created 4 components:
The 4 types of stateful* components
- SFC (Single File Component)
- Component with a template
- Component with a render function
- Component with a render function and JSX syntax
*There's one more type, a functional component, but it is stateless and therefore cannot help us in this imaginary task
So, let's check out the implementations...
Implementations
1. SFC (Single File Component)
This is the most common one and should be used as default.
The .vue
file is actually an html file that is being pre-processed by the Vue CLI to allow for special features in the template and in the style tag (e.g. scss and scoped styles)
<template>
<div>
<button v-for="(item, index) in items" :key="index" @click="onItemSelected(item)">{{item}}</button>
<p v-if="selectedItem">You selected {{selectedItem}}</p>
<p v-else >Please select your favorite</p>
</div>
</template>
<script>
export default {
name: "ListItemsSfc",
props: ['items'],
data() {
return {
selectedItem: null
}
},
methods: {
onItemSelected(item) {
this.selectedItem = item;
}
}
}
</script>
<style scoped>
button {
background: lightsteelblue;
}
</style>
2. Component with a template
This is pretty similar to SFC only you don't get the scoped styling and the syntax highlighting (since the template is actually a string)
import Vue from 'vue/dist/vue.js'; // <-- important for template components to work
Vue.component('ListItemsTemplate', {
props: ['items'],
data() {
return {
selectedItem: null
}
},
methods: {
onItemSelected(item) {
this.selectedItem = item;
}
},
template: `
<div>
<button style="background: lightsteelblue" v-for="(item, index) in items" :key="index" @click="onItemSelected(item)">{{item}}</button>
<p v-if="selectedItem">You selected {{selectedItem}}</p>
<p v-else >Please select your favorite</p>
</div>
`
});
3. Component with a render function
Allows for a more dynamic creation of the component's template.
The render function accepts a createElement
function that is used for rendering a single html element (here shortened as ce
).
The createElement
function receives a tag name, an optional data object and an optional content that can be text or additional html child elements, also created with this function.
import Vue from 'vue/dist/vue.js'; // <-- important for template components to work
Vue.component('ListItemsRender', {
props: ['items'],
data() {
return {
selectedItem: null
}
},
methods: {
onItemSelected(item) {
this.selectedItem = item;
}
},
render(ce) {
let getButtonData = (item) => {
return {
style: { background: 'lightsteelblue' },
on: { click: () => this.onItemSelected(item) }
}
};
let buttons = this.items.map(item => ce('button', getButtonData(item), item));
let statusText = this.selectedItem ? `You selected ${this.selectedItem}` :
'Please select your favorite';
return ce('div', [...buttons, ce('p',statusText)]);
}
});
4. Component with a render function and JSX syntax
It makes writing complex templates easier.
import Vue from 'vue/dist/vue.js'; // <-- important for template components to work
Vue.component('ListItemsJsx', {
props: ['items'],
data() {
return {
selectedItem: null
}
},
methods: {
onItemSelected(item) {
this.selectedItem = item;
}
},
render(h){
let buttons = this.items.map(item => <button onClick={() => this.onItemSelected(item)} style="background:lightsteelblue">{item}</button>);
let statusText = this.selectedItem ? `You selected ${this.selectedItem}` :
'Please select your favorite';
return (
<div>
{buttons}
<p>{statusText}</p>
</div>
);
}
});
And here's the final result, hosted on CodeSandbox. You can open the project and play with the components to test them out.
The final result
Let me know in the comments in case you have any general questions or any questions related specifically to one of the alternatives presented here.
Coded with love,
Lilo
Top comments (5)
thanks - very useful, to the point, compact article clarifying varied ways of vue component creation. helped me
Thanks for sharing.
You can also do it in a HTML file without compiling any js
Of course. You can also do it in React and in Angular. However, this post is about Vue. The example was simple on purpose, for illustration.
This is the most dumb comment ever...