140行代码实现时钟翻牌器

前言

时钟翻牌器效果大家或多或少都有见过,有了解过的人应该知道他的大致实现原理,理解简单,代码不简单。本文从另一个角度出发,用140行代码实现时钟翻牌器,并且你也可以扩展出不同的用法。

先来看一下效果

结尾有完整代码地址

正文

实现的原理:将翻牌的效果一分为二,第一步是翻牌,第二步是变数字,在翻页动作快要结束的时候变化数字就能达到翻牌器的效果。

实现翻牌效果

  1. 第一步实现两卡片贴合在一起翻转

核心代码很简单:

卡片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;
}
  1. 递增
  1. 递减
  1. 设置步长

这个不用通过Props设置,直接设置传入的value就可以了

封装为时钟翻牌器

页面多显示几个翻牌器,对应时分秒的十位和个位。然后对时间进行监听,设置对应的值即可,远程地址里也有代码。

结语

感兴趣的可以去试试

远程仓库地址: gitee.com/lin-zhiteng...

相关推荐
mantou13212 分钟前
我给 AI Agent 做了个「油猴」:让 Claude Code / Codex 直接用你已登录的浏览器
前端·javascript·后端
默_笙13 分钟前
🍕 一个主编、三个工种、两本手册:搭一支 AI 调研队
前端·javascript
纸片人15 分钟前
Blender 建模 + Three.js 展示:和 AI 一起做一个光储充超充站数字孪生大屏
前端
智能直播17 分钟前
网络RTMP拉流不卡顿、声音不同步?一文讲透缓冲区、时间戳与MEDAI V2实战调优
前端
第七页独白18 分钟前
汽车零件厂如何通过 QMS 真正落地 IATF 16949——QMS软件系统:品质检验-内审稽核-8d客诉管理:全星质量管理软件系统
java·前端·数据库
纸片人25 分钟前
只用 three.js + OpenStreetMap,手搓一个「成都城市 3D」数据大屏
前端
星若生辉26 分钟前
Hugo 静态站点搭建|从本地调试到上线部署实操指南
前端
沐浴露z44 分钟前
Agent 响应延迟过高?从工具治理角度提供两条思路
前端·网络
CappuccinoRose1 小时前
FormData数据处理
开发语言·前端·javascript·表单数据
飘尘2 小时前
SVG和Canvas,前端里的两支“画笔”,用的时候怎么选择?
前端·javascript·面试