
Framer 中的真实数据:时钟
2022年11月1日
尽管 Framer 已经成为了主打网页设计的建站工具,但我们依旧能够使用它进行原型设计。这个系列的文章将会利用 Framer 的 Override 特性引入一些真实数据到 Framer 中,在第一篇中,我们将利用简单的代码设计一个真实的时钟组件。
创建UI
首先,我们需要创建时钟的UI图层,它至少包含时针、分针与秒针。这里以 iOS 的时钟组件为例,你可以直接复制下面的组件到 Framer 来加速这一进程。
在制作指针时,我们将指针的部分放在一个正方形 Frame 中,这会方便我们接下来的操作。

Override
在 Framer 中新建一个 Override 文件,然后分别创建名为 Hour、Minute 和 Second 的函数组件。
export function Hour(Component): ComponentType { return (props) => { return ( <Component {...props} /> ) } } export function Minute(Component): ComponentType { return (props) => { return ( <Component {...props} /> ) } } export function Second(Component): ComponentType { return (props) => { return ( <Component {...props} /> ) } }
然后将三个Override组件分别连接到 UI 中的时针、分针、秒针中。

使用Date()
JS 提供的 Date 对象让我们可以非常方便地获取当前时间。我们利用这一功能分别获取当前的时、分、秒以及毫秒数据。为了方便使用这些数据,我们将其定义为“数字”。
const hour = Number(new Date().getHours()) const minute = Number(new Date().getMinutes()) const second = Number(new Date().getSeconds()) const millisecond = Number(new Date().getMilliseconds())
从秒针开始
我们的目标是让秒钟拥有平滑的转动效果(就像 iOS 那样),而 Framer Motion 能够为我们达成这一效果。首先,我们创建名为 “from” 与 “to” 的 Variants,设置 initial 为 “from”,设置 animate 为“to”。
export function Second(Component): ComponentType { return (props) => { const variant = { from: { }, to: { }, } return ( <Component {...props} variants={variant} initial={"from"} animate={"to"} /> ) } }
“from” 代表了我们的秒针将从什么角度开始转动,它取决于当前时间中的秒。秒针在时钟上每秒转动6度,因此我们在 “from” 中设置角度为 6 \* second。
from: { rotate: 6 * second, },
现在,我们的秒针就有了一个起始角度。但它每次只会以0 °、6 °、12 °……作为起点,为了让角度更加精确,我们加入毫秒作为参考。
from: { rotate: 6 * second + 6 * (millisecond / 1000), },
这样,我们的秒针就有了一个较为精准的起点。接下来,我们为秒针设置动画的终点 “to”,只需在起点的基础加上360°即可。此外我们要将缓动曲线设置为线性,持续时间为60秒,无限重复。
to: { rotate: 6 * second + 6 * (millisecond / 1000) + 360, transition: { duration: 60, ease: "linear", repeat: Infinity }, },
现在我们可以看到秒针已经完美的工作了。
分针与时针
对于分针与时针,我们使用相同的方法。对于分针的起始角度,我们将 “分钟(minute)” 与 “秒(second)” 结合,持续时间设置为 3600 秒(一小时)。
const variant = { from: { rotate: 6 * minute + 6 * (second / 60), }, to: { rotate: 6 * minute + 6 * (second / 60) + 360, transition: { duration: 3600, ease: "linear", repeat: Infinity, }, }, }
而时针只需使用“时(hour)” 与 “分钟(minute)”即可。在使用 hour 数据前,我们需要对数据进行一个换算,因为 hour 是以24小时格式进行计算的,而时针上的数字最大只有12。当时针进行到中午12点时(hour = 12),我们需要让 hour 返回到0,这样时针才可以正常地工作。这里只需一个简单的判断即可。
const hour12 = hour >= 12 ? hour - 12 : hour
然后同样的为时针添加 Variant 参数,需要注意的是我们要将动画的持续时间设置为43200秒(12小时)。
const hour12 = hour >= 12 ? hour - 12 : hour const variant = { from: { rotate: 30 * hour12 + 30 * (minute / 60), transition: { duration: 0, ease: "linear" }, }, to: { rotate: 30 * hour12 + 30 * (minute / 60) + 360, transition: { duration: 43200, ease: "linear", repeat: Infinity, }, }, }
完整代码
import type { ComponentType } from "react" const hour = Number(new Date().getHours()) const minute = Number(new Date().getMinutes()) const second = Number(new Date().getSeconds()) const millisecond = Number(new Date().getMilliseconds()) export function Hour(Component): ComponentType { return (props) => { const hour12 = hour >= 12 ? hour - 12 : hour const variant = { from: { rotate: 30 * hour12 + 30 * (minute / 60), transition: { duration: 0, ease: "linear" }, }, to: { rotate: 30 * hour12 + 30 * (minute / 60) + 360, transition: { duration: 43200, ease: "linear", repeat: Infinity, }, }, } return ( <Component {...props} variants={variant} initial={"from"} animate={"to"} /> ) } } export function Minute(Component): ComponentType { return (props) => { const variant = { from: { rotate: 6 * minute + 6 * (second / 60), transition: { duration: 0, ease: "linear" }, }, to: { rotate: 6 * minute + 6 * (second / 60) + 360, transition: { duration: 3600, ease: "linear", repeat: Infinity, }, }, } return ( <Component {...props} variants={variant} initial={"from"} animate={"to"} /> ) } } export function Second(Component): ComponentType { return (props) => { const variant = { from: { rotate: 6 * second + 6 * (millisecond / 1000), transition: { duration: 0, ease: "linear" }, }, to: { rotate: 6 * second + 6 * (millisecond / 1000) + 360, transition: { duration: 60, ease: "linear", repeat: Infinity }, }, } return ( <Component {...props} variants={variant} initial={"from"} animate={"to"} /> ) } }
现在,所有的指针都开始正常工作了。这是我目前利用 Framer Motion 的 Variants 特性制作的动画,可能在某些数据方面会出现准确性问题,如果你有更好地解决方案,欢迎一起交流。
Content

Framer 中的真实数据:时钟
2022年11月1日
尽管 Framer 已经成为了主打网页设计的建站工具,但我们依旧能够使用它进行原型设计。这个系列的文章将会利用 Framer 的 Override 特性引入一些真实数据到 Framer 中,在第一篇中,我们将利用简单的代码设计一个真实的时钟组件。
创建UI
首先,我们需要创建时钟的UI图层,它至少包含时针、分针与秒针。这里以 iOS 的时钟组件为例,你可以直接复制下面的组件到 Framer 来加速这一进程。
在制作指针时,我们将指针的部分放在一个正方形 Frame 中,这会方便我们接下来的操作。

Override
在 Framer 中新建一个 Override 文件,然后分别创建名为 Hour、Minute 和 Second 的函数组件。
export function Hour(Component): ComponentType { return (props) => { return ( <Component {...props} /> ) } } export function Minute(Component): ComponentType { return (props) => { return ( <Component {...props} /> ) } } export function Second(Component): ComponentType { return (props) => { return ( <Component {...props} /> ) } }
然后将三个Override组件分别连接到 UI 中的时针、分针、秒针中。

使用Date()
JS 提供的 Date 对象让我们可以非常方便地获取当前时间。我们利用这一功能分别获取当前的时、分、秒以及毫秒数据。为了方便使用这些数据,我们将其定义为“数字”。
const hour = Number(new Date().getHours()) const minute = Number(new Date().getMinutes()) const second = Number(new Date().getSeconds()) const millisecond = Number(new Date().getMilliseconds())
从秒针开始
我们的目标是让秒钟拥有平滑的转动效果(就像 iOS 那样),而 Framer Motion 能够为我们达成这一效果。首先,我们创建名为 “from” 与 “to” 的 Variants,设置 initial 为 “from”,设置 animate 为“to”。
export function Second(Component): ComponentType { return (props) => { const variant = { from: { }, to: { }, } return ( <Component {...props} variants={variant} initial={"from"} animate={"to"} /> ) } }
“from” 代表了我们的秒针将从什么角度开始转动,它取决于当前时间中的秒。秒针在时钟上每秒转动6度,因此我们在 “from” 中设置角度为 6 \* second。
from: { rotate: 6 * second, },
现在,我们的秒针就有了一个起始角度。但它每次只会以0 °、6 °、12 °……作为起点,为了让角度更加精确,我们加入毫秒作为参考。
from: { rotate: 6 * second + 6 * (millisecond / 1000), },
这样,我们的秒针就有了一个较为精准的起点。接下来,我们为秒针设置动画的终点 “to”,只需在起点的基础加上360°即可。此外我们要将缓动曲线设置为线性,持续时间为60秒,无限重复。
to: { rotate: 6 * second + 6 * (millisecond / 1000) + 360, transition: { duration: 60, ease: "linear", repeat: Infinity }, },
现在我们可以看到秒针已经完美的工作了。
分针与时针
对于分针与时针,我们使用相同的方法。对于分针的起始角度,我们将 “分钟(minute)” 与 “秒(second)” 结合,持续时间设置为 3600 秒(一小时)。
const variant = { from: { rotate: 6 * minute + 6 * (second / 60), }, to: { rotate: 6 * minute + 6 * (second / 60) + 360, transition: { duration: 3600, ease: "linear", repeat: Infinity, }, }, }
而时针只需使用“时(hour)” 与 “分钟(minute)”即可。在使用 hour 数据前,我们需要对数据进行一个换算,因为 hour 是以24小时格式进行计算的,而时针上的数字最大只有12。当时针进行到中午12点时(hour = 12),我们需要让 hour 返回到0,这样时针才可以正常地工作。这里只需一个简单的判断即可。
const hour12 = hour >= 12 ? hour - 12 : hour
然后同样的为时针添加 Variant 参数,需要注意的是我们要将动画的持续时间设置为43200秒(12小时)。
const hour12 = hour >= 12 ? hour - 12 : hour const variant = { from: { rotate: 30 * hour12 + 30 * (minute / 60), transition: { duration: 0, ease: "linear" }, }, to: { rotate: 30 * hour12 + 30 * (minute / 60) + 360, transition: { duration: 43200, ease: "linear", repeat: Infinity, }, }, }
完整代码
import type { ComponentType } from "react" const hour = Number(new Date().getHours()) const minute = Number(new Date().getMinutes()) const second = Number(new Date().getSeconds()) const millisecond = Number(new Date().getMilliseconds()) export function Hour(Component): ComponentType { return (props) => { const hour12 = hour >= 12 ? hour - 12 : hour const variant = { from: { rotate: 30 * hour12 + 30 * (minute / 60), transition: { duration: 0, ease: "linear" }, }, to: { rotate: 30 * hour12 + 30 * (minute / 60) + 360, transition: { duration: 43200, ease: "linear", repeat: Infinity, }, }, } return ( <Component {...props} variants={variant} initial={"from"} animate={"to"} /> ) } } export function Minute(Component): ComponentType { return (props) => { const variant = { from: { rotate: 6 * minute + 6 * (second / 60), transition: { duration: 0, ease: "linear" }, }, to: { rotate: 6 * minute + 6 * (second / 60) + 360, transition: { duration: 3600, ease: "linear", repeat: Infinity, }, }, } return ( <Component {...props} variants={variant} initial={"from"} animate={"to"} /> ) } } export function Second(Component): ComponentType { return (props) => { const variant = { from: { rotate: 6 * second + 6 * (millisecond / 1000), transition: { duration: 0, ease: "linear" }, }, to: { rotate: 6 * second + 6 * (millisecond / 1000) + 360, transition: { duration: 60, ease: "linear", repeat: Infinity }, }, } return ( <Component {...props} variants={variant} initial={"from"} animate={"to"} /> ) } }
现在,所有的指针都开始正常工作了。这是我目前利用 Framer Motion 的 Variants 特性制作的动画,可能在某些数据方面会出现准确性问题,如果你有更好地解决方案,欢迎一起交流。
Content

Framer 中的真实数据:时钟
2022年11月1日
尽管 Framer 已经成为了主打网页设计的建站工具,但我们依旧能够使用它进行原型设计。这个系列的文章将会利用 Framer 的 Override 特性引入一些真实数据到 Framer 中,在第一篇中,我们将利用简单的代码设计一个真实的时钟组件。
创建UI
首先,我们需要创建时钟的UI图层,它至少包含时针、分针与秒针。这里以 iOS 的时钟组件为例,你可以直接复制下面的组件到 Framer 来加速这一进程。
在制作指针时,我们将指针的部分放在一个正方形 Frame 中,这会方便我们接下来的操作。

Override
在 Framer 中新建一个 Override 文件,然后分别创建名为 Hour、Minute 和 Second 的函数组件。
export function Hour(Component): ComponentType { return (props) => { return ( <Component {...props} /> ) } } export function Minute(Component): ComponentType { return (props) => { return ( <Component {...props} /> ) } } export function Second(Component): ComponentType { return (props) => { return ( <Component {...props} /> ) } }
然后将三个Override组件分别连接到 UI 中的时针、分针、秒针中。

使用Date()
JS 提供的 Date 对象让我们可以非常方便地获取当前时间。我们利用这一功能分别获取当前的时、分、秒以及毫秒数据。为了方便使用这些数据,我们将其定义为“数字”。
const hour = Number(new Date().getHours()) const minute = Number(new Date().getMinutes()) const second = Number(new Date().getSeconds()) const millisecond = Number(new Date().getMilliseconds())
从秒针开始
我们的目标是让秒钟拥有平滑的转动效果(就像 iOS 那样),而 Framer Motion 能够为我们达成这一效果。首先,我们创建名为 “from” 与 “to” 的 Variants,设置 initial 为 “from”,设置 animate 为“to”。
export function Second(Component): ComponentType { return (props) => { const variant = { from: { }, to: { }, } return ( <Component {...props} variants={variant} initial={"from"} animate={"to"} /> ) } }
“from” 代表了我们的秒针将从什么角度开始转动,它取决于当前时间中的秒。秒针在时钟上每秒转动6度,因此我们在 “from” 中设置角度为 6 \* second。
from: { rotate: 6 * second, },
现在,我们的秒针就有了一个起始角度。但它每次只会以0 °、6 °、12 °……作为起点,为了让角度更加精确,我们加入毫秒作为参考。
from: { rotate: 6 * second + 6 * (millisecond / 1000), },
这样,我们的秒针就有了一个较为精准的起点。接下来,我们为秒针设置动画的终点 “to”,只需在起点的基础加上360°即可。此外我们要将缓动曲线设置为线性,持续时间为60秒,无限重复。
to: { rotate: 6 * second + 6 * (millisecond / 1000) + 360, transition: { duration: 60, ease: "linear", repeat: Infinity }, },
现在我们可以看到秒针已经完美的工作了。
分针与时针
对于分针与时针,我们使用相同的方法。对于分针的起始角度,我们将 “分钟(minute)” 与 “秒(second)” 结合,持续时间设置为 3600 秒(一小时)。
const variant = { from: { rotate: 6 * minute + 6 * (second / 60), }, to: { rotate: 6 * minute + 6 * (second / 60) + 360, transition: { duration: 3600, ease: "linear", repeat: Infinity, }, }, }
而时针只需使用“时(hour)” 与 “分钟(minute)”即可。在使用 hour 数据前,我们需要对数据进行一个换算,因为 hour 是以24小时格式进行计算的,而时针上的数字最大只有12。当时针进行到中午12点时(hour = 12),我们需要让 hour 返回到0,这样时针才可以正常地工作。这里只需一个简单的判断即可。
const hour12 = hour >= 12 ? hour - 12 : hour
然后同样的为时针添加 Variant 参数,需要注意的是我们要将动画的持续时间设置为43200秒(12小时)。
const hour12 = hour >= 12 ? hour - 12 : hour const variant = { from: { rotate: 30 * hour12 + 30 * (minute / 60), transition: { duration: 0, ease: "linear" }, }, to: { rotate: 30 * hour12 + 30 * (minute / 60) + 360, transition: { duration: 43200, ease: "linear", repeat: Infinity, }, }, }
完整代码
import type { ComponentType } from "react" const hour = Number(new Date().getHours()) const minute = Number(new Date().getMinutes()) const second = Number(new Date().getSeconds()) const millisecond = Number(new Date().getMilliseconds()) export function Hour(Component): ComponentType { return (props) => { const hour12 = hour >= 12 ? hour - 12 : hour const variant = { from: { rotate: 30 * hour12 + 30 * (minute / 60), transition: { duration: 0, ease: "linear" }, }, to: { rotate: 30 * hour12 + 30 * (minute / 60) + 360, transition: { duration: 43200, ease: "linear", repeat: Infinity, }, }, } return ( <Component {...props} variants={variant} initial={"from"} animate={"to"} /> ) } } export function Minute(Component): ComponentType { return (props) => { const variant = { from: { rotate: 6 * minute + 6 * (second / 60), transition: { duration: 0, ease: "linear" }, }, to: { rotate: 6 * minute + 6 * (second / 60) + 360, transition: { duration: 3600, ease: "linear", repeat: Infinity, }, }, } return ( <Component {...props} variants={variant} initial={"from"} animate={"to"} /> ) } } export function Second(Component): ComponentType { return (props) => { const variant = { from: { rotate: 6 * second + 6 * (millisecond / 1000), transition: { duration: 0, ease: "linear" }, }, to: { rotate: 6 * second + 6 * (millisecond / 1000) + 360, transition: { duration: 60, ease: "linear", repeat: Infinity }, }, } return ( <Component {...props} variants={variant} initial={"from"} animate={"to"} /> ) } }
现在,所有的指针都开始正常工作了。这是我目前利用 Framer Motion 的 Variants 特性制作的动画,可能在某些数据方面会出现准确性问题,如果你有更好地解决方案,欢迎一起交流。
Content

Framer 中的真实数据:时钟
2022年11月1日
尽管 Framer 已经成为了主打网页设计的建站工具,但我们依旧能够使用它进行原型设计。这个系列的文章将会利用 Framer 的 Override 特性引入一些真实数据到 Framer 中,在第一篇中,我们将利用简单的代码设计一个真实的时钟组件。
创建UI
首先,我们需要创建时钟的UI图层,它至少包含时针、分针与秒针。这里以 iOS 的时钟组件为例,你可以直接复制下面的组件到 Framer 来加速这一进程。
在制作指针时,我们将指针的部分放在一个正方形 Frame 中,这会方便我们接下来的操作。

Override
在 Framer 中新建一个 Override 文件,然后分别创建名为 Hour、Minute 和 Second 的函数组件。
export function Hour(Component): ComponentType { return (props) => { return ( <Component {...props} /> ) } } export function Minute(Component): ComponentType { return (props) => { return ( <Component {...props} /> ) } } export function Second(Component): ComponentType { return (props) => { return ( <Component {...props} /> ) } }
然后将三个Override组件分别连接到 UI 中的时针、分针、秒针中。

使用Date()
JS 提供的 Date 对象让我们可以非常方便地获取当前时间。我们利用这一功能分别获取当前的时、分、秒以及毫秒数据。为了方便使用这些数据,我们将其定义为“数字”。
const hour = Number(new Date().getHours()) const minute = Number(new Date().getMinutes()) const second = Number(new Date().getSeconds()) const millisecond = Number(new Date().getMilliseconds())
从秒针开始
我们的目标是让秒钟拥有平滑的转动效果(就像 iOS 那样),而 Framer Motion 能够为我们达成这一效果。首先,我们创建名为 “from” 与 “to” 的 Variants,设置 initial 为 “from”,设置 animate 为“to”。
export function Second(Component): ComponentType { return (props) => { const variant = { from: { }, to: { }, } return ( <Component {...props} variants={variant} initial={"from"} animate={"to"} /> ) } }
“from” 代表了我们的秒针将从什么角度开始转动,它取决于当前时间中的秒。秒针在时钟上每秒转动6度,因此我们在 “from” 中设置角度为 6 \* second。
from: { rotate: 6 * second, },
现在,我们的秒针就有了一个起始角度。但它每次只会以0 °、6 °、12 °……作为起点,为了让角度更加精确,我们加入毫秒作为参考。
from: { rotate: 6 * second + 6 * (millisecond / 1000), },
这样,我们的秒针就有了一个较为精准的起点。接下来,我们为秒针设置动画的终点 “to”,只需在起点的基础加上360°即可。此外我们要将缓动曲线设置为线性,持续时间为60秒,无限重复。
to: { rotate: 6 * second + 6 * (millisecond / 1000) + 360, transition: { duration: 60, ease: "linear", repeat: Infinity }, },
现在我们可以看到秒针已经完美的工作了。
分针与时针
对于分针与时针,我们使用相同的方法。对于分针的起始角度,我们将 “分钟(minute)” 与 “秒(second)” 结合,持续时间设置为 3600 秒(一小时)。
const variant = { from: { rotate: 6 * minute + 6 * (second / 60), }, to: { rotate: 6 * minute + 6 * (second / 60) + 360, transition: { duration: 3600, ease: "linear", repeat: Infinity, }, }, }
而时针只需使用“时(hour)” 与 “分钟(minute)”即可。在使用 hour 数据前,我们需要对数据进行一个换算,因为 hour 是以24小时格式进行计算的,而时针上的数字最大只有12。当时针进行到中午12点时(hour = 12),我们需要让 hour 返回到0,这样时针才可以正常地工作。这里只需一个简单的判断即可。
const hour12 = hour >= 12 ? hour - 12 : hour
然后同样的为时针添加 Variant 参数,需要注意的是我们要将动画的持续时间设置为43200秒(12小时)。
const hour12 = hour >= 12 ? hour - 12 : hour const variant = { from: { rotate: 30 * hour12 + 30 * (minute / 60), transition: { duration: 0, ease: "linear" }, }, to: { rotate: 30 * hour12 + 30 * (minute / 60) + 360, transition: { duration: 43200, ease: "linear", repeat: Infinity, }, }, }
完整代码
import type { ComponentType } from "react" const hour = Number(new Date().getHours()) const minute = Number(new Date().getMinutes()) const second = Number(new Date().getSeconds()) const millisecond = Number(new Date().getMilliseconds()) export function Hour(Component): ComponentType { return (props) => { const hour12 = hour >= 12 ? hour - 12 : hour const variant = { from: { rotate: 30 * hour12 + 30 * (minute / 60), transition: { duration: 0, ease: "linear" }, }, to: { rotate: 30 * hour12 + 30 * (minute / 60) + 360, transition: { duration: 43200, ease: "linear", repeat: Infinity, }, }, } return ( <Component {...props} variants={variant} initial={"from"} animate={"to"} /> ) } } export function Minute(Component): ComponentType { return (props) => { const variant = { from: { rotate: 6 * minute + 6 * (second / 60), transition: { duration: 0, ease: "linear" }, }, to: { rotate: 6 * minute + 6 * (second / 60) + 360, transition: { duration: 3600, ease: "linear", repeat: Infinity, }, }, } return ( <Component {...props} variants={variant} initial={"from"} animate={"to"} /> ) } } export function Second(Component): ComponentType { return (props) => { const variant = { from: { rotate: 6 * second + 6 * (millisecond / 1000), transition: { duration: 0, ease: "linear" }, }, to: { rotate: 6 * second + 6 * (millisecond / 1000) + 360, transition: { duration: 60, ease: "linear", repeat: Infinity }, }, } return ( <Component {...props} variants={variant} initial={"from"} animate={"to"} /> ) } }
现在,所有的指针都开始正常工作了。这是我目前利用 Framer Motion 的 Variants 特性制作的动画,可能在某些数据方面会出现准确性问题,如果你有更好地解决方案,欢迎一起交流。
Content

Framer 中的真实数据:时钟
2022年11月1日
尽管 Framer 已经成为了主打网页设计的建站工具,但我们依旧能够使用它进行原型设计。这个系列的文章将会利用 Framer 的 Override 特性引入一些真实数据到 Framer 中,在第一篇中,我们将利用简单的代码设计一个真实的时钟组件。
创建UI
首先,我们需要创建时钟的UI图层,它至少包含时针、分针与秒针。这里以 iOS 的时钟组件为例,你可以直接复制下面的组件到 Framer 来加速这一进程。
在制作指针时,我们将指针的部分放在一个正方形 Frame 中,这会方便我们接下来的操作。

Override
在 Framer 中新建一个 Override 文件,然后分别创建名为 Hour、Minute 和 Second 的函数组件。
export function Hour(Component): ComponentType { return (props) => { return ( <Component {...props} /> ) } } export function Minute(Component): ComponentType { return (props) => { return ( <Component {...props} /> ) } } export function Second(Component): ComponentType { return (props) => { return ( <Component {...props} /> ) } }
然后将三个Override组件分别连接到 UI 中的时针、分针、秒针中。

使用Date()
JS 提供的 Date 对象让我们可以非常方便地获取当前时间。我们利用这一功能分别获取当前的时、分、秒以及毫秒数据。为了方便使用这些数据,我们将其定义为“数字”。
const hour = Number(new Date().getHours()) const minute = Number(new Date().getMinutes()) const second = Number(new Date().getSeconds()) const millisecond = Number(new Date().getMilliseconds())
从秒针开始
我们的目标是让秒钟拥有平滑的转动效果(就像 iOS 那样),而 Framer Motion 能够为我们达成这一效果。首先,我们创建名为 “from” 与 “to” 的 Variants,设置 initial 为 “from”,设置 animate 为“to”。
export function Second(Component): ComponentType { return (props) => { const variant = { from: { }, to: { }, } return ( <Component {...props} variants={variant} initial={"from"} animate={"to"} /> ) } }
“from” 代表了我们的秒针将从什么角度开始转动,它取决于当前时间中的秒。秒针在时钟上每秒转动6度,因此我们在 “from” 中设置角度为 6 \* second。
from: { rotate: 6 * second, },
现在,我们的秒针就有了一个起始角度。但它每次只会以0 °、6 °、12 °……作为起点,为了让角度更加精确,我们加入毫秒作为参考。
from: { rotate: 6 * second + 6 * (millisecond / 1000), },
这样,我们的秒针就有了一个较为精准的起点。接下来,我们为秒针设置动画的终点 “to”,只需在起点的基础加上360°即可。此外我们要将缓动曲线设置为线性,持续时间为60秒,无限重复。
to: { rotate: 6 * second + 6 * (millisecond / 1000) + 360, transition: { duration: 60, ease: "linear", repeat: Infinity }, },
现在我们可以看到秒针已经完美的工作了。
分针与时针
对于分针与时针,我们使用相同的方法。对于分针的起始角度,我们将 “分钟(minute)” 与 “秒(second)” 结合,持续时间设置为 3600 秒(一小时)。
const variant = { from: { rotate: 6 * minute + 6 * (second / 60), }, to: { rotate: 6 * minute + 6 * (second / 60) + 360, transition: { duration: 3600, ease: "linear", repeat: Infinity, }, }, }
而时针只需使用“时(hour)” 与 “分钟(minute)”即可。在使用 hour 数据前,我们需要对数据进行一个换算,因为 hour 是以24小时格式进行计算的,而时针上的数字最大只有12。当时针进行到中午12点时(hour = 12),我们需要让 hour 返回到0,这样时针才可以正常地工作。这里只需一个简单的判断即可。
const hour12 = hour >= 12 ? hour - 12 : hour
然后同样的为时针添加 Variant 参数,需要注意的是我们要将动画的持续时间设置为43200秒(12小时)。
const hour12 = hour >= 12 ? hour - 12 : hour const variant = { from: { rotate: 30 * hour12 + 30 * (minute / 60), transition: { duration: 0, ease: "linear" }, }, to: { rotate: 30 * hour12 + 30 * (minute / 60) + 360, transition: { duration: 43200, ease: "linear", repeat: Infinity, }, }, }
完整代码
import type { ComponentType } from "react" const hour = Number(new Date().getHours()) const minute = Number(new Date().getMinutes()) const second = Number(new Date().getSeconds()) const millisecond = Number(new Date().getMilliseconds()) export function Hour(Component): ComponentType { return (props) => { const hour12 = hour >= 12 ? hour - 12 : hour const variant = { from: { rotate: 30 * hour12 + 30 * (minute / 60), transition: { duration: 0, ease: "linear" }, }, to: { rotate: 30 * hour12 + 30 * (minute / 60) + 360, transition: { duration: 43200, ease: "linear", repeat: Infinity, }, }, } return ( <Component {...props} variants={variant} initial={"from"} animate={"to"} /> ) } } export function Minute(Component): ComponentType { return (props) => { const variant = { from: { rotate: 6 * minute + 6 * (second / 60), transition: { duration: 0, ease: "linear" }, }, to: { rotate: 6 * minute + 6 * (second / 60) + 360, transition: { duration: 3600, ease: "linear", repeat: Infinity, }, }, } return ( <Component {...props} variants={variant} initial={"from"} animate={"to"} /> ) } } export function Second(Component): ComponentType { return (props) => { const variant = { from: { rotate: 6 * second + 6 * (millisecond / 1000), transition: { duration: 0, ease: "linear" }, }, to: { rotate: 6 * second + 6 * (millisecond / 1000) + 360, transition: { duration: 60, ease: "linear", repeat: Infinity }, }, } return ( <Component {...props} variants={variant} initial={"from"} animate={"to"} /> ) } }
现在,所有的指针都开始正常工作了。这是我目前利用 Framer Motion 的 Variants 特性制作的动画,可能在某些数据方面会出现准确性问题,如果你有更好地解决方案,欢迎一起交流。
Content
@2025 THE STAGE FOR JAY JI.
- 0
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 0
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
@2025 THE STAGE FOR JAY JI.
- 0
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 0
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
@2025 THE STAGE FOR JAY JI.
- 0
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 0
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
@2025 THE STAGE FOR JAY JI.
- 0
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 0
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
@2025 THE STAGE FOR JAY JI.
- 0
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 0
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9