数字滚动

来源 https://juejin.cn/post/6986453616517185567
<template>
  <component
    :is="as"
    class="scroll-num"
    :style="{ '--i': i, '--delay': delay }"
  >
    <ul ref="ul">
      <li>0</li>
      <li>1</li>
      <li>2</li>
      <li>3</li>
      <li>4</li>
      <li>5</li>
      <li>6</li>
      <li>7</li>
      <li>8</li>
      <li>9</li>
      <li>0</li>
    </ul>

    <svg width="0" height="0">
      <filter id="blur">
        <feGaussianBlur
          in="SourceGraphic"
          :stdDeviation="`0 ${blur}`"
        />
      </filter>
    </svg>
  </component>
</template>

<script>
export default {
  name: 'ScrollNum',
  props: {
    as: {
      type: String,
      default: 'div'
    },
    i: {
      type: Number,
      default: 0,
      validator: v => v < 10 && v >= 0 && Number.isInteger(v)
    },
    delay: {
      type: Number,
      default: 1
    },
    blur: {
      type: Number,
      default: 2
    }
  },
  data: () => ({ timer: null }),
  mounted () {
    const ua = navigator.userAgent.toLowerCase()
    const testUA = regexp => regexp.test(ua)
    const isSafari = testUA(/safari/g) && !testUA(/chrome/g)

    // Safari浏览器的兼容代码
    isSafari && (this.timer = setTimeout(() => {
      this.$refs.ul.setAttribute('style', `
        animation: none;
        transform: translateY(calc(var(--i) * -9.09%))
      `)
    }, this.delay * 1000))
  },
  beforeDestroy () { clearTimeout(this.timer) }
}
</script>

<style scoped>
.scroll-num {
  width: var(--width, 20px);
  height: var(--height, calc(var(--width, 20px) * 1.8));
  color: var(--color, #333);
  font-size: var(--height, calc(var(--width, 20px) * 1.1));
  line-height: var(--height, calc(var(--width, 20px) * 1.8));
  text-align: center;
  overflow: hidden;
  animation: enhance-bounce-in-down 1s calc(var(--delay) * 1s) forwards;
}

ul {
  /* padding: 0;
  margin: 0;
  list-style: none; */
  animation: move .3s linear infinite,
  bounce-in-down 1s calc(var(--delay) * 1s) forwards
}

@keyframes move {
  from {
    transform: translateY(-90%);
    filter: url(#blur)
  }
  to {
    transform: translateY(1%);
    filter: url(#blur)
  }
}

@keyframes bounce-in-down {
  from {
    transform: translateY(calc(var(--i) * -9.09% - 7%));
    filter: none
  }
  25% { transform: translateY(calc(var(--i) * -9.09% + 3%)) }
  50% { transform: translateY(calc(var(--i) * -9.09% - 1%)) }
  70% { transform: translateY(calc(var(--i) * -9.09% + .6%)) }
  85% { transform: translateY(calc(var(--i) * -9.09% - .3%)) }
  to { transform: translateY(calc(var(--i) * -9.09%)) }
}

@keyframes enhance-bounce-in-down {
  25% { transform: translateY(8%) }
  50% { transform: translateY(-4%) }
  70% { transform: translateY(2%) }
  85% { transform: translateY(-1%) }
  to { transform: translateY(0) }
}
</style>