☰
VueUse useNow:在 Vue 3 中获取响应式当前时间的完整指南
2026/10/1 1:52:42 网站建设 项目流程
  • 前端

【免费下载链接】vueuse

Collection of essential Vue Composition Utilities for Vue 3

项目地址:https://gitcode.com/gh_mirrors/vu/vueuse
点击查看免费下载

useNow是 VueUse 提供的一个轻量级组合式函数,用于在 Vue 3 应用中获取响应式的当前 Date 实例。它默认通过requestAnimationFrame驱动时间刷新,并提供pause/resume/isActive等控制能力,非常适合时钟、计时器、倒计时、时间轴等实时渲染场景。读完本文,你将掌握useNow的基础用法、controls与自定义scheduler配置、组件式调用方式,以及其底层基于shallowRef与调度器的实现原理。

快速上手:基础用法

useNow的定位非常纯粹——"Reactive current Date instance"(响应式的当前日期实例)。最简单的调用方式如下:

import { useNow } from '@vueuse/core' const now = useNow()

调用后,now是一个ShallowRef<Date>,其值会随着当前时间的推移而不断更新。在模板中直接使用即可:

<script setup lang="ts"> import { useNow } from '@vueuse/core' const now = useNow() </script> <template> <div>Now: {{ now }}</div> </template>

对应的官方演示见 demo.vue,这正是该组合式函数最典型的应用场景。由于useNow依赖浏览器端的requestAnimationFrame,它主要面向客户端渲染环境(对应测试文件也命名为index.browser.test.ts)。

选项与返回类型

useNow的完整签名如下(见 index.ts):

export function useNow(options?: UseNowOptions<false>): ShallowRef<Date> export function useNow(options: UseNowOptions<true>): { now: ShallowRef<Date> } & Pausable

它接受一个可选的UseNowOptions,目前包含两个配置项:

配置项类型默认值说明
controlsbooleanfalse是否暴露pause、resume、isActive等控制能力
scheduler(cb: Fn) => PausableuseRafFn自定义调度器,决定时间值如何被驱动刷新

其中controls会通过**条件类型(conditional type)**影响返回值结构。从源码UseNowReturn的定义(index.ts)可以看出:

  • controls: false(默认)时返回ShallowRef<Date>,即直接返回时间 ref;
  • controls: true时返回{ now: ShallowRef<Date> } & Pausable,即解构出now以及pause、resume、isActive。

启用 controls

import { useNow } from '@vueuse/core' const { now, pause, resume } = useNow({ controls: true })

这是官方文档给出的第二种用法。拿到控制能力后,你可以随时暂停时间刷新:

// 暂停更新时间 pause() // 恢复更新时间 resume() // 读取当前是否处于刷新状态 // isActive: Readonly<ShallowRef<boolean>>

Pausable接口定义在 packages/shared/utils/types.ts,包含三个成员:

  • isActive:只读的ShallowRef<boolean>,标识调度器当前是否在运行;
  • pause:临时暂停效果执行;
  • resume:恢复效果执行。

源码原理:shallowRef + 调度器

useNow的实现非常精简(index.ts),核心逻辑只有三步:

export function useNow(options: UseNowOptions<boolean> = {}): UseNowReturn<boolean> { const { controls: exposeControls = false, scheduler = useRafFn, } = options const now = shallowRef(new Date()) const update = () => now.value = new Date() const controls = scheduler(update) if (exposeControls) { return { now, ...controls, } } else { return now } }

三个关键设计点值得注意:

1. 使用shallowRef而非ref。now存储的是一个Date对象,但每次刷新时都是整体替换为新的new Date()实例,并不涉及对 Date 内部属性的深层追踪,因此用shallowRef即可获得最优性能,避免不必要的深层响应式开销。源码中useNow被标记了@__NO_SIDE_EFFECTS__,意味着在构建时会被识别为无副作用函数,便于摇树优化。

2. 刷新逻辑与调度器解耦。update = () => now.value = new Date()只是单纯地把当前时间写入 ref,至于"多久更新一次"完全由scheduler决定。默认调度器是useRafFn,即每一帧(约 60fps)刷新一次。

3.controls展开传递。当exposeControls为true时,直接把调度器返回的Pausable控制项展开到返回值中,实现{ now, pause, resume, isActive }的结构。

默认调度器 useRafFn 的底层行为

默认调度器useRafFn实现在 useRafFn/index.ts,它基于浏览器的requestAnimationFrameAPI 工作,并通过isActive、previousFrameTimestamp和rafId维护循环状态。其关键行为包括:

  • 创建时默认立即启动(immediate = true),并调用tryOnScopeDispose(pause),因此在组件卸载或作用域销毁时会自动停止刷新,无需手动清理;
  • 支持fpsLimit限制每秒执行帧数(默认null不限制),内部通过比较delta与1000 / limit决定是否跳过当前帧;
  • pause()会调用window.cancelAnimationFrame(rafId)取消下一帧注册,resume()则重置时间戳后重新注册。

由于这些行为被封装成Pausable,useNow得以完全复用而无需重复实现定时逻辑。

自定义调度器:控制刷新频率

scheduler选项的存在让useNow的刷新策略变得完全可定制。任何符合(cb: Fn) => Pausable签名的函数都可以作为调度器,例如改用useIntervalFn按固定时间间隔刷新(这在useNow的官方测试 index.browser.test.ts 中有直接验证):

import { useNow } from '@vueuse/core' import { useIntervalFn } from '@vueuse/shared' // 每 1000ms 刷新一次时间 const { now } = useNow({ controls: true, scheduler: cb => useIntervalFn(cb, 1000), })

甚至可以实现"惰性启动"——默认调度器useRafFn的immediate为true,创建即开始刷新;如果你希望一开始不刷新、等到某个时机再resume(),可以这样写(同样有测试用例覆盖,见 index.browser.test.ts):

import { useNow } from '@vueuse/core' import { useRafFn } from '@vueuse/core' const { now, resume } = useNow({ controls: true, scheduler: cb => useRafFn(cb, { immediate: false }), })

测试验证了该场景下:创建后即使推进 50ms,now值也保持不变;调用resume()后时间才开始前进。

注意:scheduler的类型ConfigurableScheduler定义于 packages/core/_configurable.ts,即(cb: Fn) => Pausable,要求返回的调度器必须同时具备暂停与恢复能力,这保证了controls模式下pause/resume始终可用。

组件式用法:<UseNow>

除了组合式函数,VueUse 还为useNow提供了对应的渲染函数组件UseNow(见 component.ts)。该组件将useNow({ controls: true })的返回值用reactive()包装后,通过作用域插槽暴露给模板:

<template> <UseNow v-slot="{ now, pause, resume }"> Now: {{ now }} <button @click="pause()"> Pause </button> <button @click="resume()"> Resume </button> </UseNow> </template>

组件内部逻辑(component.ts)非常直白:接收scheduler属性透传给useNow,并强制controls: true以获得完整控制项;然后通过slots.default(data)将响应式数据注入插槽。由于组件始终开启 controls,插槽里总是能拿到now、pause、resume、isActive。

行为验证与测试保障

useNow的行为在 index.browser.test.ts 中得到了系统验证,测试使用vi.useFakeTimers()模拟时间推进,覆盖了四条核心路径:

  1. 默认行为:useNow()返回的时间戳不大于当前Date.now();
  2. 惰性调度器:immediate: false时时间不前进,resume()后才前进;
  3. 组件渲染:<UseNow>通过作用域插槽正确输出时间;
  4. 控制能力:对useRafFn与useIntervalFn(cb, 50)两种调度器分别验证pause()后时间冻结、resume()后继续前进。

这些测试从侧面印证了useNow的接口契约:默认即用、可暂停可恢复、调度器可替换。

相关资源索引

  • 文档:packages/core/useNow/index.md
  • 实现源码:packages/core/useNow/index.ts
  • 组件封装:packages/core/useNow/component.ts
  • 演示示例:packages/core/useNow/demo.vue
  • 浏览器测试:packages/core/useNow/index.browser.test.ts
  • 默认调度器:packages/core/useRafFn/index.ts
  • 可配置类型与默认窗口:packages/core/_configurable.ts
  • Pausable类型定义:packages/shared/utils/types.ts
  • 导出入口:packages/core/index.ts(export * from './useNow')

useNow通过"响应式 ref + 可替换调度器"的简洁抽象,把"当前时间"这个最常见的实时数据源变成了一个可组合、可控制、可测试的 Vue 响应式原语。无论是做简单时钟,还是构建需要精确控制刷新节奏的时间组件,它都是一个值得优先选择的基础工具。

  • 前端

【免费下载链接】vueuse

Collection of essential Vue Composition Utilities for Vue 3

项目地址:https://gitcode.com/gh_mirrors/vu/vueuse
点击查看免费下载
上一篇:终极V2EX增强工具:V2EX-Plus让你的社区体验提升10倍
下一篇:【亲测免费】 推荐项目:贡献模板(Contributing Template)

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询