Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to fade in images when loaded with Vue

I created this component that fades in an image once it is loaded to the client. I would think there is a more Vue-like way to solve this, like using Vue events, but could not find it. What is the Vue way to detect when an image is loaded?

https://codepen.io/kslstn/pen/ooaPGW

Vue.component('imageThatFadesInOnLoad',{

  data: function(){
    return {
      src: 'http://via.placeholder.com/350x150',
      loaded: false,
    }
  },

  mounted: function () {
    var image = new Image()
    var that =  this
    this.loaded = image.addEventListener('load', function(){that.onLoaded()}) // This is the key part: it is basically vanilla JS
    image.src = this.src
  },

  methods:{
    onLoaded(){
      this.loaded = true
    }
  },

  template: `
    <div class="wrapper">
      <transition name="fade">
        <img class="icon" v-bind:src="src" v-if="loaded">&nbsp;
      </transition>
   </div>
  `
})

new Vue({
  el: '#wrapper'
});
.wrapper{
  width: 350px;
  height: 150px;
  background: slategrey;
}
.fade-enter-active {
  transition: opacity 3s ease-in-out;
}
.fade-enter-to{
  opacity: 1;
}
.fade-enter{
  opacity: 0;
}
<script src="https://unpkg.com/[email protected]/dist/vue.js"></script>
<div id="wrapper">
<image-that-fades-in-on-load></image-that-fades-in-on-load>
</div>
like image 847
kslstn Avatar asked Nov 28 '17 15:11

kslstn


2 Answers

You can use the v-on: (or @ shorthand) syntax for binding to any DOM event. In your case the load event, which is triggered when the image is loaded.

Because you are loading the image "the DOM way" you can't use v-if because then Vue will not render the element (but you need it to, so the image src is fetched). Instead you can use v-show, which will render but hide the element.

Vue.component('imageThatFadesInOnLoad', {
  data: function() {
    return {
      src: 'http://via.placeholder.com/350x150',
      loaded: false,
    }
  },
  methods: {
    onLoaded() {
      this.loaded = true;
    }
  },
  template: `
    <div class="wrapper">
      <transition name="fade">
        <img class="icon" v-bind:src="src" v-on:load="onLoaded" v-show="loaded">&nbsp;
      </transition>
   </div>
  `
});

new Vue({
  el: '#wrapper'
});
.wrapper {
  width: 350px;
  height: 150px;
  background: slategrey;
}

.fade-enter-active {
  transition: opacity 3s ease-in-out;
}

.fade-enter-to {
  opacity: 1;
}

.fade-enter {
  opacity: 0;
}
<script src="https://unpkg.com/[email protected]/dist/vue.js"></script>

<div id="wrapper">
  <image-that-fades-in-on-load></image-that-fades-in-on-load>
</div>
like image 113
yuriy636 Avatar answered Oct 07 '22 03:10

yuriy636


Just to provide a slightly different approach to the answers above, using a native CSS solution instead of the Vue <Transition> way.

In the code below, we just add a class to the <img> when it loads triggering a transition.

<template>
  <img
    :class="imgIsLoaded ? 'show' : ''"
    src="myImg.jpg"
    loading="lazy"
    @load="imgLoadedMethod"
  >
</template>
<script>
export default {
  data () {
    return {
      imgIsLoaded: false
    }
  },
  methods: {
    imgLoadedMethod () {
      this.imgIsLoaded = true
    }
  }
}
</script>
<style scoped>
img {
  opacity: 0;
  transition: 3s;
}

img.show {
  opacity: 1;
}
</style>
like image 24
Leopold Kristjansson Avatar answered Oct 07 '22 01:10

Leopold Kristjansson