There are multiple ways to create an image uploader in Vue.js. Majority of the developers prefer using a third party package (NPM) to get it done. However, in this example you’re going to learn how to do it in pure Vue.js. This will also keep your app size relatively smaller. You may follow along the article to know the ins and outs with an example. Alternatively, you can jump to the bottom of the article to get the working code.
First of all, create a new file (component) in your Vue.js project. You can name it anything, I’m going with ImageUploader.vue. In this component, we’re going to have four smaller components, sectioned by <div>’s. The first component will let the user pick an image file (PNG,JPG,JPEG,WEBP,GIF, etc) from their computer. The second component will show an image preview after they pick an image. The third component will let the user upload or cancel the image. The fourth component will show the user a message when the image upload is in progress.
So, in the <template> section, write down the following code:
The image uploader template code
<template>
<div>
<h2>Image uploader</h2>
<div
class="np-image-upload-picker"
v-if="imageFile == null || imageFile.length == 0"
>
Select an image file:
<input type="file" @change="showImagePreview($event)" accept="image/*" />
</div>
<div
class="np-image-preview"
v-if="imageFile != null && imageFile.length != 0"
>
<img class="np-preview" :src="imageFile" />
</div>
<div v-if="imageFile != null && imageFile.length != 0 && !isImageUploading">
<button
class="np-upload-btn np-upload-btn-cancel"
v-on:click="clearImage"
>
Cancel
</button>
<button
class="np-upload-btn np-upload-btn-confirm"
v-on:click="uploadImage"
>
Upload
</button>
</div>
<div class="np-upload-in-progress" v-if="isImageUploading">
Please wait while your file is being uploaded ...
</div>
</div>
</template>
Code language: HTML, XML (xml)
On line 6, you’ll see that I’m showing the first section only when they haven’t already selected a file. On line 9, I’m showing a file picker button to the user and where they pick a file (as directed by the @change function). I’m then calling the showImagePreview() function and passing in the change event as $event. $event in Vue.js is same as passing the native event in JavaScript. You’re soon going to see what’s going on in the showImagePreview() function.
On line 15, I’m showing the image preview to the user. Not that there’s a check at the <div> of this section on line 13 that hides the image preview altogether if they don’t choose a file.
On line 17, I’m showing two buttons to the user named ‘Cancel’ or ‘Upload’. I’m showing these buttons only if there’s some image in the state, and the upload is not already in progress.
On line 28, I’ve created an upload button and on line 20, a clear button. You’re soon going to learn the functionalities of these button below. Finally, on line 31, I’m showing a message to the user when their image upload is in progress.
Now, let’s jump to the script and check all the functionalities you need. You need to write the following script in the same component that contains the above template code.
The image uploader script code
<script>
export default {
name: "ImageUploader",
data() {
return {
imageFile: null,
input: null,
isImageUploading: false,
};
},
methods: {
showImagePreview(event) {
this.input = event.target;
if (this.input.files && this.input.files[0]) {
let reader = new FileReader();
reader.onload = (e) => {
this.imageFile = e.target.result;
};
reader.readAsDataURL(this.input.files[0]);
}
},
uploadImage() {
this.isImageUploading = true;
setTimeout(() => {
console.log(this.imageFile);
this.isImageUploading = false;
this.clearImage();
alert("Image uploaded sucessfully!");
}, 3000);
},
clearImage() {
this.imageFile = null;
this.input = null;
},
},
};
</script>
Code language: HTML, XML (xml)
In the script above, if you look at the data() method, I’m maintaining 3 local states named:
imageFile: This state keeps the actual image file in base64 format
input: This state directly binds to the user input data (when they pick an image from their computer file browser)
isImageUploading: This state is a flag to check whether or not an image upload is in progress
On line 12, there’s the method called showImagePreview(). Have a look at what all these statements mean here with their number lines:
13: I’m copying and storing native JavaScript event.target into the local state (this.input).
14: I’m checking if the user has actually selected any file and that there’s at least one file selected
15: I’m creating a new FileReader to read the selected image and convert it into base64 format. I’m doing this here because most of the servers don’t support image files directly but only when converted to base64.
16: I’ve called a callback function called onload as soon as FileReader finishes converting the file. Once the conversion is done, I’ve stored the converted image file directly in the local state this.imageFile.
19: I’ve read the file as a data url (base64 format) so that you can preview that on the browser
That was it about the preview functionality.
On line 31, I’ve created a clearImage method. This method clears the local states I’m maintaining for storing the image files. I’m calling this method on clicking the ‘Cancel’ button.
On line 22, there’s the uploadImage() method. Here, I’ve set the isImageUploading flag to true. This ensures that the user can see the image upload progress message. It also hides the sections where you can pick a new image to upload. Not that I’ve simulated an API call with the JavaScript’s setTimeout method. This will simulate a 3 seconds (3000 milliseconds) API call. You need to call the actual POST method here to upload the image and then call the clearImage method as I’ve done here.
I’ve also added some CSS styles, which you can modify as per your requirements:
<style scoped>
.np-image-preview {
padding: 20px;
background: #eee;
border-radius: 16px;
margin: 10px;
}
.np-image-upload-picker {
padding: 20px;
background: #eee;
border-radius: 16px;
margin: 10px;
}
img.np-preview {
background-color: #fff;
border: 1px solid #ddd;
padding: 5px;
height: 200px;
border-radius: 16px;
margin: 10px;
}
.np-upload-btn {
margin: 10px;
border: 0px !important;
font-size: 18px;
padding: 16px 60px !important;
font-weight: 300;
color: #fff;
border-radius: 30px;
}
.np-upload-btn-confirm {
background: rgb(0, 163, 73) !important;
}
.np-upload-btn-cancel {
background: rgb(122, 0, 31) !important;
}
.np-upload-in-progress {
background: #eee !important;
margin: 10px;
border: 0px !important;
font-size: 18px;
padding: 16px 60px !important;
font-weight: 300;
color: #000;
border-radius: 30px;
}
</style>
Code language: HTML, XML (xml)
You can find the finished code from my repos here: