How to Build Vue Components like a Pro 😎

Rajat S
Bits and Pieces
Published in
8 min readJun 13, 2018

--

Vue is one of the most rapidly growing JavaScript frameworks in today’s world. Described as an “Intuitive, Fast, and Composable” MVVM for building interactive interfaces, Vue has become every developer’s favorite JavaScript framework for developing interactive web apps and interfaces. This is quite obvious with its 97K GitHub ⭐️ since its release in 2014.

Tip: Use Bit to share and reuse your components between apps. It helps you discover and play with components, using them to build faster. Give it a try.

UI spinners with Bit: Choose, play, use

Unlike Angular, which is based on the good old Model-View-Controller architecture, Vue follows a Model-View-View-Model system.

Another great thing about Vue is that it has single file components. This means that you can write the template, the script, and the style in a single .vue file.

<template>
<p>({greeting })</p>
</template>
<script>
module.exports = {
data: function () {
return {
greeting: 'Hello'
}
}
}
</script>
<style scoped>
p {
font-size: 2em;
text-align: center;
}
</style>

In this post, I will portray some of the best practices that you may want to keep in mind when building an advanced Vue App.

App Setup

There are many different ways that you can choose from for creating a Vue App. If you are a newbie, you can check out out this JS Fiddle Hello World Example to try out Vue.

In this post I am going to use the Vue CLI to create a Vue Project. First, open a command terminal in your system and write the following command to install the Vue CLI:

$ npm install --global @vue/cli

You can now create a Vue project! So lets go ahead and do that:

$ vue create vue-app
$ cd vue-app

This will create a new Vue project called vue-app. You can name it something else if you want.

Build Vue Components with vue-class-component

Take a look at the code snippet at the top of and you will see that you have a data function that returns an object. If you want to pass any handlers, you would have to write a method object.

vue-class-component reduces the component development process by allowing developers to add data properties and handlers directly as properties to the class.

Open your project directory in a code editor (I ❤️ VS Code). In your src folder, you will notice two files: App.vue and main.js.

Developers with prior experience in libraries like React can say that the main.js file is equivalent to React’s index.js. Meaning this the actual file that gets launched when you run commands like yarn serve or yarn build.

Re-write the main.js file with the following code:

Basically, we are first grabbing a div element that has “app” as the id from the public/index.html file and then we are rendering the App component inside it.

You now need to create this App component inside the App.vue file. Open the App.vue file and replace the default code with this:

Here, I first have created a simple template that has a div with a message inside it. The script imports the Vue package and the Component function from vue-class-component. You also need to install this package in your project.

$ yarn add vue-class-component

Next, I am decorating the App class with the Component function. This function has an object that you can pass in options.

If you are using VS Code, you will see that you are now getting an error on App. This is because VS Code by default does not accept experimental decorator. To solve this issue, create a new file called jsconfig.json in the project’s root directory. Here, you are telling the Vue Compiler to allow experimental decorators in your code:

{
"compilerOptions": {
"experimentalDecorators": true
}
}

Reload the editor and you will see the error disappear!

Now we answer the question, “Why should I use vue-class-component instead of Vue’s traditional components?”

In a traditional component, you are required to write a data function that returns an object. To change anything in your component, you will then write methods such an onClick.

const TraditionalComp = {
data() {
return {message: "Batman"}
},
methods:{
onClick() {
this.message = "Bruce Wayne"
}
}
}

But in vue-class-component, you directly write the onClick method. All that’s left to do is link it to the template. You can do this by writing @click="onClick" inside the template’s h1 tag.

Run the Vue app using the yarn serve command, and you will see it work like this:

Define your Props with vue-property-decorator

You can also use vue-property-decorator to define the properties directly on the class. And that too is done with a simple @Prop() decorator. This method of prop declaration lets us keep our classes simple.

First, install the vue-property-decorator package in your project:

$ yarn add vue-property-decorator

Another great thing about this package is that it also includes the vue-class-component inside it. So you can instead import the Component from the vue-property-decorator package.

Inside the App.vue file, re-write the code as shown below:

Here, I am first importing the Component and Prop from the vue-property-decorator package. Then inside the App class, I am using the @Prop decorator to set the default value of the message.

And that’s it! You are now passing the message as prop to our code, and it also has a default value.

Define the Content’s Place in Components with Vue Slots

Vue’s slots lets you tell your code where you want your content to be in the component. This may sound confusing now, so let’s see what slots actually do for us with some coding.

Back in the main.js file, re-write the code inside render like this:

render: h => (
<App>
<h1>Superman</h1>
</App>
)

If you take a look at the app in your browser, you will see that nothing has changed. This is because you have not specified any place for the new text inside the template in App.vue file. This is where slots come into play.

Inside App.vue‘s template, write two new slots that wrap the original h1 tag.

<template>
<div>
<slot name="header"></slot>
<h1 @click="onClick">
{{message}}
</h1>
<slot name="footer"></slot>
</div>
</template>

Your app still won’t render the new text. That’s because the compiler now doesn’t know which slot to put the new text in. I want the text to be in the bottom slot. I have given this slot a name of footer.

Go to main.js file, and add an attribute of slot="footer" to the new text. This will then render the new text.

But your render method is a bit unwieldy now. Let’s see how you can use slots to take care of that.

Use Slots to Create Layouts

You can also use slots to create custom layouts that can be used to specify where each piece of your app or component should be placed.

Create a new file called Layout.vue inside the src/components folder. Inside this file, write a template element as shown below:

<template>
<div>
<slot name="header"></slot>
<slot name="body"></slot>
<slot name="footer"></slot>
</div>
</template>

Next, go into the App.vue file and delete everything inside the template tag. Then, inside the script tag, import the Layout.vue that you just created, like this:

import Layout from './components/Layout';

You also need to tell the Component decorator that you are using the Layout as a component.

export default Component({
components: {Layout},
})

You can now use the Layout as a component inside the template tag. I am going to also add a few text tags.

<template>
<Layout>
<h1 slot="header">How To Build Vue Apps Like A Pro 😎</h1>
<h2 slot="body"> by Rajat S</h2>
<h3 slot="footer">Technical Content Writer</h3>
</Layout>
</template>

Make sure that you have added a slot attribute with the appropriate name, else the text tags will not get rendered.

Passing Props using Vue Slot Scope

By combining your components with slots, you can pass the component’s data into slot using slot-scope. You can pass props down from Parent components to Child components without coupling them together.

Go to the App.vue file and inside the template tag, wrap the Layout inside a Settings tag.

<template>
<Settings>
<Layout slot-scope="{header}">
<h1 slot="header">{{header}}</h1>
<h2 slot="body"> by Rajat S</h2>
<h3 slot="footer">Technical Content Writer</h3>
</Layout>
</Settings>
</template>

Import the Settings inside the script tag,

import Settings from './components/Settings.vue';

Tell the Component decorator that you are using Settings as a component.

export default Component({
components: {Layout, Settings},
})

Now, you actually need to create the Settings component. So go to src/components and create a file named Settings.vue. Write this code inside it:

Inside the template tag, I have a root div that has slot inside it. Inside this slot, I’m binding :header to header.

Moving on to the script tag, I am first importing the Vue package and the Component decorator from vue-class-component package.

Then I create a Header class inside the Component decorator. This class contains the data that I want to pass on to the header prop.

Passing Props to Functional Templates

Functional templates allows you to create a component that only has a template tag and exposes the props into the template.

Inside the src/components folder, create a new file called Header.vue write this code inside it:

<template functional>
<h1 slot="header">{{props.header}}</h1>
</template>

The term functional here is used to indicate that this file only has a simple template. Repeat this for Body.vue and Footer.vue files.

Return to the App.vue file and re-write the template like this:

<template>
<Settings>
<Layout slot-scope="{header, body, footer}">
<Header slot="header" :header="header"></Header>
<Body slot="body" :body="body"></Body>
<Footer slot="footer" :footer="footer"></Footer>
</Layout>
</Settings>
</template>

You also need to write the import statements for the Header, Body, Footer inside the file’s script tag:

import {Header, Body, Footer} from './components';

And tell the Component decorator that you are using these as components.

export default Component({
components: {
Settings,
Layout,
Header,
Body,
Footer,
},
})

But the code still won’t work. Because the import statement that you just wrote is not entirely correct. To solve this issue, create a new file called index.js inside src/components.

export {default as Header} from ‘./Header.vue’;
export {default as Body} from ‘./Body.vue’;
export {default as Footer} from ‘./Footer.vue’;

With this, you have created Functional Templates in Vue that allows us to pass our props from a Parent component to a Child component, without having to write much code.

Conclusion…

Vue is a software technology that is being widely used across the world for web development. Vue is actually a JavaScript framework with various optional tools for building user interfaces.

One of the main factor’s behind Vue’s success is that it is very easy to learn and it’s even easier to build awesome apps with it.

I hope this post helped you understand Vue better and how you can build better apps with it. Stay tuned for similar posts on Vue, React, and other popular frameworks/libraries. Feel free to comment and ask anything!

--

--