Components in Vue.js
Introduction
Vue.js components are important to understand as you work with Vue.js. In this tutorial we are going to dig into Vue.js components, understanding the basics and applying them to an application. Let's get started.
What Are Components?
Components enable us to break the complexity of an application into tiny chunks. For example, a typical web application will have sections like header, sidebar, content, and footer.
Vue.js allows us to break each of these sections into separate modular code called components. These components can be extended, and then attached to the application you are working on. Components are a great way of reusing your code throughout your application.
Let's say you have a blog application, and you would like to display a list of blog posts. Using a Vue component, you can do:
<blog-post></blog-post>
Vue handles the rest.
Create a simple HTML page that mounts a Vue instance to your DOM element. You will use this to learn about components. Here is what the sample HTML page should look like:
<!DOCTYPE html> <html> <head> <title>VueJs Components</title> </head> <body> <!-- Div where Vue instance will be mounted --> <div id="app"></div> <!-- Vue.js is included in your page via CDN --> <script src="https://unpkg.com/vue"></script> <script> // A new Vue instance is created and mounted to your div element new Vue({ el: '#app', data: { domain: 'Tutsplus' }, template: '<p>Welcome to </p> }); </script> </body> </html>
In the above, you created a simple Vue instance, with no component factor in the code. Now if you want the welcome message to appear twice, how do you do it? Try getting that to work.
Your guess might be to have the div
where the Vue instance is mounted appear twice. That will not work. Try changing it from id
to class
so you have this:
<!DOCTYPE html> <html> <head> <title>VueJs Components</title> </head> <body> <!-- Div where Vue instance will be mounted --> <div class="app"></div> <div class="app"></div> <!-- Vue.js is included in your page via CDN --> <script src="https://unpkg.com/vue"></script> <script> // A new Vue instance is created and mounted to your div element new Vue({ el: '.app', data: { domain: 'Tutsplus' }, template: '<p>Welcome to </p> }); </script> </body> </html>
It still will not work!
The only way to get around this is to create a component. How do you create a component?
Components are created using the Vue.component()
constructor. This constructor takes two parameters: the name of your component (which can also be called the tag name), and an object containing options for your component.
Let's create a component using what you have above.
Vue.component('welcome-message', { data: function() { return { domain: 'Tutsplus' } }, template: '<p>Welcome to </p>' })
In the above, the component name is called welcome-message
. Your component can have whatever name you choose. Yet it is important that the name does not interfere with any HTML tags, as you will not want to override it.
The options object passed to the constructor contains the data and template. When creating components, your data should be a function, as you can see above. The data being held should then be returned as an object.
In situations where there are no data to pass, you can pass only the template like so:
Vue.component('welcome-message', { template: '<p>Welcome to Tutsplus</p>' })
With that done, you can use your component in your application by calling it like a regular HTML element using the name you passed to the constructor. It is called like this: <welcome-message></welcome-message>
.
To output the template more than once, you call the component as many times as you want—as I did below.
<!DOCTYPE html> <html> <head> <title>VueJs Components</title> </head> <body> <!-- Div where Vue instance will be mounted --> <div id="app"> <welcome-message></welcome-message> <welcome-message></welcome-message> <welcome-message></welcome-message> <welcome-message></welcome-message> </div> <!-- Vue.js is included in your page via CDN --> <script src="https://unpkg.com/vue"></script> <script> Vue.component('welcome-message', { data: function() { return { domain: 'Tutsplus' } }, template: '<p>Welcome to </p>' }) // A new Vue instance is created and mounted to your div element new Vue({ el: '#app' }); </script> </body> </html>
From the above, this will display the welcome message four times.
Store Data in Components
Above I mentioned that data has to be a function, and the information it holds has to be returned as an object. Why is it like that?
When returned data is not an object, the components that make use of that data share the same source: shared data. Thus a change in data for one component affects the other component. This is not the same when the data is returned as an object.
It is important to see how this works practically. First, let's see a situation where data is returned as an object.
<!DOCTYPE html> <html> <head> <title>VueJs Components</title> </head> <body> <!-- Div where Vue instance will be mounted --> <div id="app"> <welcome-message></welcome-message> <welcome-message></welcome-message> </div> <!-- Vue.js is included in your page via CDN --> <script src="https://unpkg.com/vue"></script> <script> var data = { name: 'Henry' } Vue.component('welcome-message', { data: function() { return data }, template: '<p>Hello , welcome to TutsPlus (<button @click="changeName">Change Name</button>)</p>', methods :{ changeName: function() { this.name = 'Mark' } } }) // A new Vue instance is created and mounted to your div element new Vue({ el: '#app' }); </script> </body> </html>
Can you guess what is happening above?
There are two components, and both components share the same data source as the data is not returned as an object. How do you prove I am right? When you view the above page from your browser, you will see that a change in one component results in a change in the data of the other component. How is it supposed to be?
Like this:
<!DOCTYPE html> <html> <head> <title>VueJs Components</title> </head> <body> <!-- Div where Vue instance will be mounted --> <div id="app"> <welcome-message></welcome-message> <welcome-message></welcome-message> </div> <!-- Vue.js is included in your page via CDN --> <script src="https://unpkg.com/vue"></script> <script> Vue.component('welcome-message', { data: function() { return { name: 'Henry' } }, template: '<p>Hello , welcome to TutsPlus (<button @click="changeName">Change Name</button>)</p>', methods :{ changeName: function() { this.name = 'Mark' } } }) // A new Vue instance is created and mounted to your div element new Vue({ el: '#app' }); </script> </body> </html>
Here the data is returned as an object, and a change in one component does not affect the other. The function is executed for the individual component. When building your applications, it is important you do not forget this.
Creating and Using Components
Using the lessons learned thus far, let us implement this in a new Vue.js project started from scratch using vue
-
cli
. If you do not have vue
-
cli
installed on your machine, you can do that by running:
npm install -g vue-cli
Start your new Vue.js project:
vue init webpack vue-component-app
Navigate to your application, install the dependencies, and run your dev server using the commands below.
cd vue-component-app npm install npm run dev
First, you'll rename the HelloWorld
component that was created when you initialized your application to Hello.vue. You'll then register this component as a global component to be used in your application.
So your Hello component should look like this.
#src/components/Hello.vue <template> <div class="hello"> <p>Welcome to TutsPlus </p> <hr> <button @click="changeName">Change Display Name</button> </div> </template> <script> export default { name: 'Hello', data () { return { name: 'Henry' } }, methods: { changeName () { this.name = 'Mark' } } } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped> h1, h2 { font-weight: normal; } ul { list-style-type: none; padding: 0; } li { display: inline-block; margin: 0 10px; } a { color: #42b983; } </style>
Nothing serious is happening here. You have your welcome text displaying the welcome message and a name which is passed as data. When the button underneath the welcome message gets clicked, the changeName
method is called. This changes the name from Henry to Mark.
To use this component globally it has to be registered. Can you guess where that will be done? If you said main.js, you are absolutely correct.
To register a component, you import it and then use the Vue.component()
constructor to set it up. Try that on your own.
I bet you got that to work. Here is how things should look in your main.js file.
#src/main.js // The Vue build version to load with the `import` command // (runtime-only or standalone) has been set in webpack.base.conf with an alias. import Vue from 'vue' import App from './App' import Home from './components/Hello' Vue.config.productionTip = false Vue.component('display-name', Home) /* eslint-disable no-new */ new Vue({ el: '#app', template: '<App/>', components: { App } })
Nothing new here except the line that imports your Hello component. The component is then registered using the constructor. Finally, for this part, the component needs to be displayed using the component name you entered. In this case, the component is display-name. This will be done in your App.vue file.
Open up src/App.vue and make it look like this.
#src/App.vue <template> <div id="app"> <display-name/> </div> </template> <script> export default { } </script> <style> #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>
With your server on, point your browser to http://localhost:8080. Click on the button and the name should change.
Let's see how to use a component locally.
Create a file called Detail.vue in your components directory. This component will not do anything special—it will be used in the Hello component.
Make your Detail.vue file look like this.
#src/components/Detail.vue <template> <div class="hello"> <p>This component is imported locally.</p> </div> </template> <script> export default { name: 'Detail' } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped> h1, h2 { font-weight: normal; } ul { list-style-type: none; padding: 0; } li { display: inline-block; margin: 0 10px; } a { color: #42b983; } </style>
To use it in the Hello component, you start by importing it, as you did with the Hello component. Next, you register it, but this time you will not make use of the Vue.component()
constructor.
You register it using the components object inside your exports. The name of the component which will be used as the element tag has to be passed as a value to the object. With that done, you can now use the element tag to output the component.
To understand all that, here is how the Hello component should look.
#src/components/Hello.vue <template> <div class="hello"> <p>Welcome to TutsPlus </p> <hr> <button @click="changeName">Change Display Name</button> <!-- Detail component is outputted using the name it was registered with --> <Detail/> </div> </template> <script> // Importation of Detail component is done import Detail from './Detail' export default { name: 'HelloWorld', data () { return { name: 'Henry' } }, methods: { changeName () { this.name = 'Mark' } }, /** * Detail component gets registered locally. * This component can only be used inside the Hello component * The value passed is the name of the component */ components: { Detail } } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped> h1, h2 { font-weight: normal; } ul { list-style-type: none; padding: 0; } li { display: inline-block; margin: 0 10px; } a { color: #42b983; } </style>
Refresh your page to see the new page.
Scoping Component Styles
Vue.js allows you to give global and local styling for your components. What do I mean? There might be scenarios where you want certain elements in a component to be styled differently from their counterparts in another component. Vue.js has got you covered on that.
A good example is available in the little app you just built. The styles in your App.vue are global; how is that possible? Open your App.vue, and the style section looks like this.
<style> #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>
This is different from that of Detail.vue, which looks like this.
<style scoped> h1, h2 { font-weight: normal; } ul { list-style-type: none; padding: 0; } li { display: inline-block; margin: 0 10px; } a { color: #42b983; } </style>
Adding scoped
to the style tag makes all the difference. Try editing one of the component styles by removing scoped
, and you will see how that works out.
Conclusion
That was a long one, and I trust you enjoyed it.
Now you know how to work effectively with components. You understand how to construct a component in an existing application. When working with vue-cli, you can also create and use components—locally and globally. When you want to use a particular style for a component, you saw how to do that using scoped.
You can now go on to build a complex Vue.js application that uses components. Understand that Vue.js allows you to reuse code—your headers, footer, login panel, and search bar can be used as components.
from Envato Tuts+ Tutorials
Comments
Post a Comment