
Custom events in Vue with $emit and Responsive Image goodness
Vue provides great functionality when creating components. One great thing is $emit. You can not only trigger a custom event but you can also send data through it.
This article discusses the use of $emit
with the implementation of responsive-image, the result will be similar to the image below:

According to Vuejs.org:
$emit: Trigger an event on the current instance. Any additional arguments will be passed into the listener’s callback function.
Lets implement a responsive image in Vue to utilize the $emit
functionality.
Step 1:
Lets start by a clean html template:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html>
<html>
<head>
<title>BetterImage Test</title>
</head>
<body>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
</body>
</html>
Nothing fancy here.
Step 2:
Now lets add Vue goodness to it.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html>
<html>
<head>
<title>Image Test</title>
</head>
<body>
<div id="app">
<h1>{{ message }}</h1>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script type="text/javascript">
const app = new Vue({
el: "#app",
data(){
return {
message: 'HELLO'
}
}
});
</script>
</body>
</html>
Your result shouldn't look different that the following image:

Step 3:
Let's add a basic code to the application so that it will show our low-resolution image only. I'm calling this component, BetterImage
.
As you can notice I've also added other properties like orignalUrl, lowresUrl, biWidth, biHeight
for future use.
The naming convention of properties in declaration is camelCase while in HTML, the naming convention is kebab-case.
The plan here is that first a low-res image is downloaded, and along-side a high-res image is also downloaded in the background, so that when the high-res image is downloaded, it is then presented with a nice effect.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template id="better-image">
<div>
<img :src="url" :width="biWidth" :height="biHeight">
</div>
</template>
<script type="text/javascript">
Vue.component('better-image', {
template: '#better-image',
mounted() {
this.url = this.lowresUrl;
},
data() {
return {
url: ''
}
},
props: ['orignalUrl', 'lowresUrl', 'biWidth', 'biHeight']
});
</script>
As the application is loaded, it will retrive a low-res image. It's worth mentioning here that I'm using Cloudinary for this example, it gives you a flexible API for image manipulations so you can request an image with specific operation on demand like this:
http://res.cloudinary.com/YOUR_USER_NAME/image/upload/w_25,q_auto:low/RESOURCE_NAME_WITH_.EXTENSION
Here, w_25 means width of 25 pixels, and q_auto:low means serve me image of low quality. More on this: https://cloudinary.com/documentation/image_transformations
Your image will result will look similar to the image below:

Step 3 (Final Step):

Now we have basic functionality, let's add the rest of the code.
What I want for my image, I want to have an image of low quality to show-up first with a blur and desaturated effect while the orignal high-res image is being downloaded in the background, once it is downloaded, the image will have a transition to a colored image and a de-bluring effect, so let's get right to it:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html>
<html>
<head>
<title>Image Test</title>
</head>
<style type="text/css">
.upgraded img {
animation: unblur 1.2s ease-out;
}
@keyframes unblur {
0% {
filter: blur(15px) grayscale(100%);
} 100% {
filter: blur(0px) grayscale(0);
}
}
.initial-state {
overflow: hidden;
display: inline-block;
}
.initial-state img {
filter: blur(15px) grayscale(100%);
}
</style>
<body>
<div id="app">
<better-image
@downloaded="imageDownloaded"
orignal-url="http://res.cloudinary.com/stahiralijan/image/upload/v1516685215/20180123_102510_lg2p5n.jpg"
lowres-url="http://res.cloudinary.com/stahiralijan/image/upload/w_25,q_auto:low/v1516685215/20180123_102510_lg2p5n.webp"
bi-width="800" bi-height="600"></better-image>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<template id="better-image">
<div :class="{ 'initial-state': loading, 'upgraded':!loading }">
<img :src="url" :width="biWidth" :height="biHeight">
</div>
</template>
<script type="text/javascript">
Vue.component('better-image', {
template: '#better-image',
mounted() {
this.url = this.lowresUrl;
this.downloadImage();
},
data() {
return {
loading: true,
url: ''
}
},
props: ['orignalUrl', 'lowresUrl', 'biWidth', 'biHeight'],
methods: {
downloadImage() {
// Taking advantage of WebAPI
let img = new Image();
let that = this;
img.onload = () => {
setTimeout(() => {
that.url = img.src;
that.loading = false;
that.$emit('downloaded', true);
img = null;
}, 1200);
};
img.src = this.orignalUrl;
}
}
});
const app = new Vue({
el: "#app",
methods: {
imageDownloaded: (e) => {
console.log("Image downloaded?",e);
}
}
});
</script>
</body>
</html>
The code above shows the use of $emit
function which trigger an event called downloaded, we have set
Our final product will look somthing similar to this:
