Skip to content
Logo Theodo

Medium-like Image Loading with Vue.js (part 1)

Louis Zawadzki4 min read

When I’m stuck on a train or queuing at the supermarket I usually read one or two articles on Medium.

There’s plenty of stuff that I really love about Medium. Like the email they send me every morning. Or the personal recommendations on their main page.

And the blurry image loading. I mean, seriously, the first time I noticed it I was like:
jimesTooper

If you don’t know what I’m talking about, click on this link and see how the top image is displayed.

I recently started using Vue.js and I thought, well, let’s see if we can build a Vue.js component to do this!

How it works

So I wondered, how do this thing work? Fortunately José M. Perez has done a wonderful (Medium) blog post explaining the principle of this technique. He even provided us with a plain javascript implementation.

If you don’t want to read the whole article, the core principle is really simple:

Let’s start

For our example, imagine our HTML looks just like this:

<!DOCTYPE html>
<html>
<head>
  <style>
    img {
      width: 100%;
    }
  </style>
</head>
<body>
  <img
    src="https://cdn-images-1.medium.com/max/1800/1*sg-uLNm73whmdOgKlrQdZA.jpeg"
  ></img>
</body>
</html>


It’s very simple: it displays one image.

First let’s include Vue.js, our .js script and substitute the img tag by a custom one that will call our component, such as blurry-image-loader:

<!DOCTYPE html>
<html>
<head>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.26/vue.min.js"></script>
  <style>
    img {
      width: 100%;
    }
  </style>
</head>
<body>
  <blurry-image-loader
    src="https://cdn-images-1.medium.com/max/1800/1*sg-uLNm73whmdOgKlrQdZA.jpeg"
    small-src="https://cdn-images-1.medium.com/freeze/max/27/1*sg-uLNm73whmdOgKlrQdZA.jpeg?q=20"
  ></blurry-image-loader>
  <script src="vue-blurry-image-loader.js"></script>
</body>
</html>

Yay! Now that our HTML is ready, let’s create our script! First of all, we have to create a new Vue instance and to register our component:

Vue.component('blurry-image-loader', {})

new Vue({
  el: 'body'
})

Allright. As you probably saw earlier, our HTML component has two attributes: the url of the image in full size (src) and the smaller image (small-src). We can register those attributes as props in our Vue.js component:

Vue.component('blurry-image-loader', {
  props: [
    'src',
    'smallSrc'
  ]
})

N.B.: we have to use camelCase in javascript, so small-src becomes smallSrc.
Ok let’s go on step-by-step: let’s say the template of our component will be an image with the low-res image:

Vue.component('blurry-image-loader', {
  props: [
    'src',
    'smallSrc'
  ],
  template: '<img :src=smallSrc></img>'
})

So now if you open your HTML file in your browser, you should see a blurry image. But that’s not going to work with that template, we need the src attribute of the img element to change when our real image is loaded. So we need a kind of changing props, which is in fact a … data!

Let’s call it imageSrc and initialize it to the value of smallSrc:

Vue.component('blurry-image-loader', {
  props: [
    'src',
    'smallSrc'
  ],
  data: function () {
    return {
      imageSrc: this.smallSrc
    }
  },
  template: '<img :src=imageSrc></img>'
})

Good! We’re nearly there.
Now we need to load the real image when the component is created, and once this is done we have to change the value of imageSrc. Vue.js components have a ready attribute which gives us the possibility to execute a function once the component is ready. I believe this sounds like the right place to do our loading!

(N.B.: in Vue 2 the ready atribute is now called mounted)

(N.B.: as pointed out by Bokkeman in the comments, to prevent trouble with your browser cache set your image src attribute after the onload event handler)

Vue.component('blurry-image-loader', {
  props: [
    'src',
    'smallSrc'
  ],
  data: function () {
    return {
      imageSrc: this.smallSrc
    }
  },
  template: '<img :src=imageSrc></img>',
  // use mounted in Vue.js 2.0
  ready: function () {
    var img, that
    img = new Image()
    that = this
    img.onload = function(){
      that.imageSrc = that.src
    }

    img.src = this.src
  }
})

And voilà! We have achieved this with actually fewer lines of code than I thought!

You can check out my Codepen to see it live (I’ve added a small timeout to make sure you see the blurry image).

I you liked this article please share it and keep checking out this blog, I’m currently writing part 2 which will show how to smooth the unblurring!

To discover how to achieve the exact same effect with transitions head to part 2 over here.

Liked this article?