翻牌器
翻牌器
ScrollCom.vue
<template> <ul class="flex"> <ScrollNum v-for="(num, idx) of numArr" :key="idx" as="li" :i="num" :delay="idx + 1" /> </ul> </template> <script> import ScrollNum from '/ScrollNum.vue' export default { name: 'ScrollCom', components: { ScrollNum }, data: () => ({ num: 886 }), computed: { numArr () { const str = String(this.num) let arr = [] for (let i = 0; i < str.length; i++) { arr.push(parseInt(str[i])) } return arr } }, mounted () { setInterval(() => this.num++, 10000) } } </script> <style scoped> .flex { display: flex; } ul { padding: 0; margin: 0; list-style: none; } </style>
ScrollNum.vue
<template> <component :is="as" class="scroll-num" :class="{ 'border-animate': showAnimate }" :style="{ '--i': i, '--delay': delay }" @animationend="showAnimate = false" > <ul ref="ul" :class="{ animate: showAnimate }"> <li>0</li> <li v-for="item in 9" :key="item">{{ item }}</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, showAnimate: true }), watch: { i () { this.showAnimate = true } }, 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)) }, beforeUnmount () { clearTimeout(this.timer) } } </script> <style scoped> .scroll-num { width: var(--width, 20px); /* var(自定义值, 默认值) */ 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; } .animate { animation: move 0.3s linear infinite, bounce-in-down 1s calc(var(--delay) * 1s) forwards; } .border-animate { animation: enhance-bounce-in-down 1s calc(var(--delay) * 1s) forwards; } ul { padding: 0; margin: 0; list-style: none; transform: translateY(calc(var(--i) * -9.09%)); } @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% + 0.6%)); } 85% { transform: translateY(calc(var(--i) * -9.09% - 0.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>
请用今天的努力,让明天没有遗憾。