Introduction to Vue.js - part two - components

Introduction to Vue.js - part two - components

Published 12. jul 2018 06:28 by Stein Ove Helset

In the second part of this tutorial we are going to turn the logo uploader into a Vue.js component that can be reused.

Adding the CSS

If you haven't read the first part of this series you can find it here

The first thing we can do is to add the necessary styles to hide the default upload field and show a button instead. Add this somewhere in the style-tag:

.image-uploader {
    position: relative;
    .image-uploader .fileinput {
        width: 200px;
        height: 40px;
        opacity: 0;

    .image-uploader .uploadbutton {
        width: 200px;
        height: 40px;
        pointer-events: none;
        position: absolute;
        top: 0;
        left: 0;

We need to set the image-uploader class to be position relative. The reason we do this is because when we use position absolute on the uploadbutton, we want it to be positioned relative to the image-uploader. The fileinput class is set to be the same size as the button we place on top of is so that no matter where you click on the button you will actually click the hiddeninput field. To make it possible to click the hidden input field we need to place the uploadbutton on top of it using position absolute. We also added the pointer-events: none so that clicks on the button will be ignored.

Vue.js component

We can begin by adding this to the top of our script tag (Over new Vue({):

Vue.component('upload-image', { // Upload-image is the name of the component
	template: ` // Create the template
		<div class="image-uploader">
			<input type="file" class="fileinput" @change="handleFileUpload"> // When the file is added, we call the handleFileUpload method

			<button class="uploadbutton">Choose picture</button>
	methods: {
		handleFileUpload: function(event) {
			var file =[0]; // Get the file input field

			var reader = new FileReader(); // Create a JS FileReader instance
			reader.readAsDataURL(file); // Convert the file into base64 data

			reader.onloadend = () => { // When the reader is finished, this function is called
				var mimetype = this.base64MimeType(reader.result); // Get the file's mimetype

				if (/(jpe?g|png|gif)$/i.test(mimetype)) { // Check if the mime type is a picture (jpg, png, gif)
					this.$emit('change', reader.result); // We use $emit to tell our parent component that 'change' is triggered, and pass back the result
		base64MimeType: function(encoded) { // Method for checking the image mime type
			var result = null;

			if (typeof encoded !== 'string') { // Make sure the data we try to check is not just a string
				return result;

			var mime = encoded.match(/data:([a-zA-Z0-9]+\/[a-zA-Z0-9-.+]+).*,.*/); // Regex for checking that the data is actually base64 data

			if (mime && mime.length) { // If the regex had a match, it's base64 and we can return the mime type
				result = mime[1];

			return result;

Now there is only two more steps and the first is to add the component to our form. The name of the component we created is upload-image, and that is also the name we need to use when we insert the component we created. Replace the old <input field=""> element with this code.

<upload-image v-on:change="onFileChange"></upload-image>

We added a v-on:change="onFileChange" attribute to the component. If you look up again at the code for the upload-image component you can see that if the mime type is actually a image, we emit back to the parent component a signal to tell them that it has 'change'. When the component receives the 'change' signal we now can call our onFileChange method.

We also need to do a little change to our old onFileChange method. We now accept a parameter to the method called base64. When the method is called we assign the base64 data to our logo field.

onFileChange(base64) {
    this.logo = base64

Share this post


Add comment