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...

相关推荐
小新讲网安9 小时前
HTTP请求走私攻击实战:CL.TE与TE.CL绕过前端服务器全解析
服务器·前端·网络·web安全·http·架构·漏洞
风骏时光牛马9 小时前
AI办公系统异常事件复盘分析
前端
console.log('npc')9 小时前
React 19 + Vite 企业级前端项目:从零搭建到规范交付
前端·react.js·前端框架
程序员黑豆9 小时前
Java字符串常量池完全指南:原理、intern()方法与性能优化最佳实践
java·前端·ai编程
光影少年9 小时前
react离线缓存、图片缓存方案
开发语言·前端·javascript·react native·react.js·缓存·前端框架
Canace9 小时前
笔记本都合上了,Claude 为什么还能在手机上执行电脑上装的技能?
前端·人工智能·ai编程
cyadyx10 小时前
Vite 比 Webpack 构建效率更高
前端·webpack·node.js·vite
mCell12 小时前
AI 时代 SVG 画图的潜力
前端·agent·svg
我命由我1234518 小时前
CesiumJS 笔记 - 获取容器中心点、Cartesian3 clone 方法、修改 Cartesian3 对象的高度
前端·javascript·css·前端框架·html·html5·js
Hopebearer_19 小时前
页面突然只剩 DOM?一次静态资源版本错配排查
前端·部署