前言
时钟翻牌器
效果大家或多或少都有见过,有了解过的人应该知道他的大致实现原理,理解简单,代码不简单。本文从另一个角度出发,用140行代码实现时钟翻牌器,并且你也可以扩展出不同的用法。
先来看一下效果
结尾有完整代码地址
正文
实现的原理:将翻牌的效果一分为二,第一步是翻牌,第二步是变数字,在翻页动作快要结束的时候变化数字就能达到翻牌器的效果。
实现翻牌效果
- 第一步实现两卡片贴合在一起翻转
核心代码很简单:
卡片1从0到-180deg
,卡片2从180deg到0deg
。
tsx
/** 上一次的数字下标 */
const [lastNumInd, setLastNumInd] = useState<NumItem>(order === 'asc' ? value : ((9 - value) as NumItem));
/** 当前的数字下标 */
const [currentNumInd, setCurrentNumInd] = useState<NumItem>(order === 'asc' ? value : ((9 - value) as NumItem));
const baseStyle = useMemo(() => {
return {
transition: 'transform 0.5s linear',
transform: `rotateX(0deg)`,
};
}, []);
/** 预备滚动样式*/
const preScrollStyle = useMemo(() => {
return {
transition: 'transform 0.5s linear',
transform: `rotateX(-180deg)`,
};
}, []);
/** 滚动样式*/
const scrollStyle = useMemo(() => {
return {
transform: `rotateX(180deg)`,
};
}, []);
return (
<Frame>
{Array.from({ length: 10 }).map((num, index) => {
return (
<Card
key={index}
style={currentNumInd == index ? baseStyle : lastNumInd === index ? preScrollStyle : scrollStyle}
>
{order === 'asc' ? index : 9 - index}
</Card>
);
})}
</Frame>
);
还有在卡片样式中添加一个很重要的样式代码
,将背面面对我们的元素隐藏起来
css
//元素的背面在 3D 变换中是否可见。
backface-visibility:hidden;
接下来将最外层元素的背景设置为跟卡片一样的颜色,这样在翻转的时候背景就有颜色了。到这里基本就已经完成了。
变化数字
在第一步的结尾可以看到,显示的数字总是少一半,接下来我们只要把那一半的数字补上就行了。
再加一个额外的卡片,前一半时间显示原数字
,后一半时间显示要变化的数字
。这样完整的效果就出来了。
核心代码
tsx
const changeNum = (newValue: NumItem) => {
let pref = currentNumInd;
let result = newValue;
setLastNumInd(pref);
setCurrentNumInd((order === 'asc' ? result : 9 - result) as NumItem);
//毫秒级时间戳
let startTime = dayjs().valueOf();
let time: any = null;
const fn = () => {
let endTime = dayjs().valueOf();
let diffTime = endTime - startTime;
if (diffTime >= 280) {
setResultNum(result);
cancelAnimationFrame(time);
return;
}
time = requestAnimationFrame(fn);
};
fn();
};
return (
<>
<Frame>
{/* 真正的屏幕上的数字 */}
<Card>{resultNum}</Card>
{/* 只为模拟9个数字卡片 */}
{Array.from({ length: 10 }).map((num, index) => {
return (
<Card
key={index}
style={currentNumInd == index ? baseStyle : lastNumInd === index ? preScrollStyle : scrollStyle}
>
{order === 'asc' ? index : 9 - index}
</Card>
);
})}
</Frame>
</>
);
一共140行代码,轻松拿下。
额外扩展
我这边就扩展了递减
tsx
export type NumItem = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
interface Props {
/** 正序还是倒序*/
order?: 'asc' | 'desc'; //asc:正序,desc:倒序
value: NumItem;
}
- 递增
- 递减
- 设置步长
这个不用通过Props
设置,直接设置传入的value
就可以了
封装为时钟翻牌器
页面多显示几个翻牌器,对应时分秒的十位和个位。然后对时间进行监听,设置对应的值即可,远程地址里也有代码。
结语
感兴趣的可以去试试
远程仓库地址: gitee.com/lin-zhiteng...