需求描述
写一个数字滚轮,实现类似老虎机的效果,可以指定数字
实现思路
这个数字滚动组件的核心实现思路可以概括为:
- 视觉原理
- 每个数字位用一个固定高度的容器,通过 overflow: hidden 只显示一个数字
- 容器内部包含完整的 0-9 序列,通过上下平移显示不同数字
- 重复放置首尾数字(0)实现无缝滚动效果
- 动画实现
- 使用 CSS animation 实现两个关键动画:
- 滚动中:无限循环向上平移实现滚动效果
- 停止时:精确平移到目标数字的位置
- 控制逻辑
- Vue 管理组件状态(rolling)控制动画切换
- 通过 CSS 变量(--num)动态计算每个数字的最终停止位置
- 使用 setTimeout 控制滚动持续时间
实现细节
页面结构
每一位数字都是这么个结构
滚动效果的实现
所谓的滚动其实就是那一长溜的数字不断重复从上到下或者从下到上这个操作,所以外层realtive,内层absolute,加上动画
那一长溜的数字最终的停止位置是需要根据这一位上的显示数字来确定的,因此需要动态算出来,在这个组件里面是下面标黄的来算
javascript
<div
:class="['TigerNumbers', rolling ? 'rolling' : 'stop']"
:style="{ '--num': ((n || 10) - 10) * 1.5 + 'em' }"
>
动画分为两种:
- 滚动的动画。translateY从0到-100%,不断循环
css
@keyframes NumberRoll {
0% {
transform: translateY(0);
}
100% {
transform: translateY(-100%);
}
}
- 最终的停止动画。就是translateY从0到算出来的要停下来的位置
css
@keyframes NumberStop {
0% {
transform: translateY(0);
}
100% {
transform: translateY(calc(var(--num)));
}
}
数据设计
- 用一个数组来存要显示的数字
- 用一个rolling变量来标记现在是滚动状态还是停止滚动状态
组件代码
vue
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script src="./js/vue.min.js"></script>
<title>Title</title>
</head>
<body>
<div id="vue_root">
<div class="Tiger">
<div v-for="(n, index) in numbers" :key="index" class="TigerItem">
<div
:class="['TigerNumbers', rolling ? 'rolling' : 'stop']"
:style="{ '--num': ((n || 10) - 10) * 1.5 + 'em' }"
>
<div>0</div>
<div>9</div>
<div>8</div>
<div>7</div>
<div>6</div>
<div>5</div>
<div>4</div>
<div>3</div>
<div>2</div>
<div>1</div>
<div>0</div>
</div>
</div>
</div>
</div>
</body>
<script>
let vm = new Vue({
el: "#vue_root",
data() {
return {
rolling: true,
numbers: [5, 3, 8], // 你可以根据需要修改数字数组
delaySec: 2, // 你可以根据需要修改 delaySec 的默认值
};
},
mounted() {
setTimeout(() => {
this.rolling = false;
}, this.delaySec * 1000);
},
})
</script>
<style>
.Tiger {
display: flex;
}
.TigerItem {
width: 1em;
height: 1.5em;
position: relative;
overflow: hidden;
background-color: lightgreen;
margin-right: 0.5em;
}
.TigerNumbers {
position: absolute;
width: 100%;
text-align: center;
}
.TigerNumbers > div {
line-height: 1.5em;
height: 1.5em;
}
.TigerNumbers.rolling {
animation: NumberRoll 0.3s infinite linear;
}
.TigerNumbers.stop {
animation: NumberStop 0.6s forwards;
}
@keyframes NumberRoll {
0% {
transform: translateY(0);
}
100% {
transform: translateY(-100%);
}
}
@keyframes NumberStop {
0% {
transform: translateY(0);
}
100% {
transform: translateY(calc(var(--num)));
}
}
</style>
</html>