[Vuejs]-Blink an image on scroll

2👍

A few things to try…

  1. Don’t start manipulating the dom with $ref

Instead, create a variable which will trigger changes in the dom

methods: {
  scrollAnimation() {
    this.showSupport = window.pageYOffset > 3000 && window.pageYOffset < 3600
  }
}
<div>
  <img v-if="showSupport" class="blink" src="../../assets/images/247-on.png">
  <img v-else src="../../assets/images/247-off.png">
</div>
  1. Blinking I would advise using css animations (@keyframes). This way you can control the timing of the blink without anything in the script. It would just start blinking as soon as it’s visible on the page.
.blink {
  animation: blink 1s infinite;
}

@keyframes blink {
    0% {opacity: 0}
    49%{opacity: 0}
    50% {opacity: 1}
}

Hope this helps.

1👍

Just wanted to add a quick demo for future readers, based on t3__rry’s comment on how scroll based events which are not optimized/debounced can lead to serious performance issue; as well as Mulhoon’s nice advice on utilizing CSS @keyframes for blinking animation:

new Vue({
  el: '#app',

  data() {
    return {
      blinkRate: 1000,
      blinkCount: 3,
      blinking: false,
      blinkTimeoutId: -1,

      state: false,
      currentPos: window.pageYOffset
    }
  },

  mounted() {
    window.addEventListener('scroll', _.debounce(() => {
      this.currentPos = window.pageYOffset;

      if (this.currentPos > 3000 && this.currentPos < 3600) {
        this.state = true;
      } 
      else {
        this.state = false;
      }
    }), 100);
  },

  methods: {
    blink() {
      if (this.blinkTimeoutId > -1) {
        clearTimeout(this.blinkTimeoutId);
      }

      this.blinking = true;

      this.blinkTimeoutId = setTimeout(() => {
        this.blinking = false;

      }, 1000 * this.blinkCount);
    }
  },

  watch: {
    state() {
      this.blink();
    }
  }
});
#app {
  background-color: gainsboro;
  height: 2000vh;
  padding: 10px;
}

.page-offset {
  position: fixed;
  top: 20px;
  right: 20px;
}

.blinker > div {
  border-radius: 50%;
  border: 2px solid white;
  color: white;
  font-weight: bold;
  height: 35px;
  left: 20px;
  line-height: 35px;
  padding: 5px;
  position: fixed;
  text-align: center;
  top: 20px;
  vertical-align: middle;
  width: 35px;
}

.blinker.animate > div {
  animation: blink 1s infinite;
}

.blinker .on {
  background-color: green;
}

.blinker .off {
  background-color: crimson;
}

@keyframes blink {
  0% {
    opacity: 0
  }
  49% {
    opacity: 0
  }
  50% {
    opacity: 1
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

<div id="app">
  <div :class="['blinker', { 'animate': blinking } ]">
    <div class="on" v-if="state">ON</div>
    <div class="off" v-else>OFF</div>
  </div>

  <code class="page-offset">pageYOffset: {{Math.floor(currentPos)}}</code>
</div>
👤Yom T.

Leave a comment