滚动时闪烁图像



我的目的是让图像在滚动上闪烁 3 次(如亮灯,然后关闭,连续 3 次,延迟 1 秒),然后保持打开状态,直到用户向下滚动超过 3600 像素。

我添加了事件侦听器:

created() {
  window.addEventListener('scroll', this.scrollAnimation)
}

在滚动 i 上发射方法scrollAnimation

methods: {
  scrollAnimation() {
    let currentPos = window.pageYOffset
    if (currentPos > 3000 && currentPos < 3600) {
      this.$refs.supportOff.style.display = 'none'
      this.$refs.supportOn.style.display = 'block'
    } else {
      this.$refs.supportOff.style.display = 'block'
      this.$refs.supportOn.style.display = 'none'
    }
  }
}

这是图像的模板:

<div class="support__image-wrapper">
  <img ref="supportOff" class="support__image support__image_on" src="../../assets/images/247-off.png">
  <img ref="supportOn" class="support__image support__image_off" src="../../assets/images/247-on.png">
</div>

现在这段代码有效,当我向下滚动 3000 像素但不低于 3600 像素时,它显示 247 打开的图像并隐藏 247 关闭的图像。但是,闪烁它存在一个问题,如果我使用 setInterval每次用户在 3000 到 3600 像素之间滚动时都会触发它。实现这种闪烁的最佳方法是什么?

尝试一些方法...

  1. 不要开始用$ref操纵 dom

相反,创建一个变量,它将触发 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. 闪烁我建议使用 css 动画 ( @keyframes )。这样,您可以控制闪烁的时间,而无需脚本中的任何内容。一旦它在页面上可见,它就会开始闪烁。
.blink {
  animation: blink 1s infinite;
}
@keyframes blink {
    0% {opacity: 0}
    49%{opacity: 0}
    50% {opacity: 1}
}

希望这有帮助。

只是想为未来的读者添加一个快速演示,基于 t3__rry 关于未优化/去抖动的基于滚动的事件如何导致严重性能问题的评论; 以及Mulhoon关于使用CSS @keyframes进行闪烁动画的好建议:

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>

最新更新