最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to fade in images when loaded with Vue - Stack Overflow

programmeradmin2浏览0评论

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?

Vueponent('imageThatFadesInOnLoad',{

  data: function(){
    return {
      src: '',
      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="/[email protected]/dist/vue.js"></script>
<div id="wrapper">
<image-that-fades-in-on-load></image-that-fades-in-on-load>
</div>

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>

Share Improve this question edited Nov 29, 2017 at 8:30 kslstn asked Nov 28, 2017 at 15:35 kslstnkslstn 1,6461 gold badge20 silver badges36 bronze badges 2
  • @load="onLoaded"? (or v-on:load="onLoaded") jsfiddle.net/vcL986Lx – yuriy636 Commented Nov 28, 2017 at 15:46
  • Somehow that doesn't work in a template: codepen.io/kslstn/pen/dZgqNW I can't find documentation on v-on:load, but maybe it is called when the Vue app starts to load? At that time the template wouldn't be done rendering yet. – kslstn Commented Nov 29, 2017 at 8:22
Add a comment  | 

3 Answers 3

Reset to default 16

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>

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>

To make transitions work when you dynamically replace cached images, you need to add a unique key. Otherwise vue's compiler will only replace the content of the element for efficiency and the transition will not be triggered.

<template>
  <div :style="{width: width+'px', height: height+'px'}">
    <transition name="fade">
      <img
        v-show="loaded"
        @load="onImageLoad"
        :src="src"
        :alt="alt"
        :width="width"
        :height="height"
        :key="src"
      />
    </transition>
  </div>
</template>
<script>
export default {
  props: ["src", "width", "height", "alt"],
  data() {
    return {
      loaded: false,
    };
  },
  methods: {
    onImageLoad() {
      this.loaded = true;
    },
  },
  watch: {
    src: {
      handler() {
        this.loaded = false;
      },
      immediate: true,
    },
  },
};
</script>
<style scoped>
.fade-enter-active {
  transition: opacity 1s ease-in-out;
}
.fade-enter-to {
  opacity: 1;
}
.fade-enter {
  opacity: 0;
}
</style>
发布评论

评论列表(0)

  1. 暂无评论