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

相关推荐
腾讯TNTWeb前端团队5 小时前
helux v5 发布了,像pinia一样优雅地管理你的react状态吧
前端·javascript·react.js
范文杰9 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪9 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪9 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy10 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom10 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom10 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom10 小时前
React与Next.js:基础知识及应用场景
前端·面试·github
uhakadotcom11 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试
uhakadotcom11 小时前
Node.js 包管理器:npm vs pnpm
前端·javascript·面试