几乎所有用 JavaScript 编写的应用程序都以某种方式处理时间或日期。一开始,这仅限于内置的 Date API。该 API 包含基本功能,但其功能非常有限。 Moment.js 等第三方库以及后来的 Intl API 和新的 Temporal API 等内置 API 为处理时间和日期提供了更大的灵活性。 Moment.js 的兴衰 Moment.js 是一个 JavaScript 库,具有用于处理时间和日期的强大实用程序。它包含基本 Date API 中缺少的功能(例如时区操作),并使许多常见操作变得更简单。 Moment 还包括格式化日期和时间的函数。它成为许多不同应用程序中广泛使用的库。 然而,Moment 也存在一些问题。它是一个大型库,可以显着增加应用程序的包大小。由于该库不支持 Tree Shaking(现代捆绑程序的一项功能,可以删除库中未使用的部分),因此即使您只使用其中的一两个函数,整个 Moment 库也会包含在内。 Moment 的另一个问题是它创建的对象是可变的。在 Moment 对象上调用某些函数会产生副作用,并会改变该对象的值。这可能会导致意外的行为或错误。 2020 年,Moment 的维护者决定将库置于维护模式。没有进行任何新功能开发,维护人员建议不要将其用于新项目。 还有其他 JavaScript 日期库,例如 date-fns,但有一个新的参与者,一个直接内置于 JavaScript 中的 API:Temporal。这是一个新标准,填补了原始 Date API 的漏洞,并解决了 Moment 和其他库中发现的一些限制。 什么是时间? Temporal 是一个新的时间和日期 API,被添加到 ECMAScript 标准中,该标准定义了现代 JavaScript。截至 20266 年 3 月,它已达到 TC39 流程(监督 JavaScript 语言提案和补充的委员会)的第 4 阶段,并将包含在下一版本的 ECMAScript 规范中。它已经在多种浏览器中实现:Chrome 144+ 和 Firefox 139+,Safari 预计很快也会跟进。不支持的浏览器和 Node.js 也可以使用 polyfill。 Temporal API 创建的对象通常代表时间上的时刻。这些可以是给定时区的全时和日期戳,也可以是没有任何时区或日期信息的“挂钟”时间的通用实例。 Temporal 的一些主要功能包括:

带或不带日期的时间。 Temporal 对象可以表示特定日期的特定时间,或不带任何日期信息的时间。也可以表示没有时间的特定日期。 时区支持。时间对象完全了解时区,并且可以跨不同时区进行转换。 Moment 也支持时区,但它需要额外的 moment-timezone 库。 不变性。一旦创建了 Temporal 对象,就无法更改。时间算术或时区转换不会修改底层对象。相反,它们生成一个新的 Temporal 对象。 基于 1 的索引。Date API(以及 Moment)的常见错误来源是月份的索引为零。这意味着一月是第 0 个月,而不是我们在现实生活中所理解的第 1 个月。 Temporal 通过使用基于 1 的索引来修复此问题 — 一月是第 1 个月。 它内置于浏览器中。由于 Temporal 是浏览器本身的一个 API,因此它不会增加应用程序的包大小。

还需要注意的是,Date API 不会消失。虽然 Temporal 取代了此 API,但它并未被删除或弃用。如果浏览器突然删除 Date API,许多应用程序就会崩溃。但是,还要记住,Moment 现在被视为处于维护模式的遗留项目。 在本文的其余部分中,我们将介绍一些将基于 Moment 的代码迁移到新的 Temporal API 的“秘诀”。让我们开始重构吧! 创建日期和时间对象 在我们可以操作日期和时间之前,我们必须创建代表它们的对象。要创建表示当前日期和时间的 Moment 对象,请使用 moment 函数。 const now = moment(); 控制台.log(现在); // 时刻<2026-02-18T21:26:29-05:00>

现在可以根据需要格式化或操作该对象。

// 转换为UTC //警告:这会改变 Moment 对象并将其置于 UTC 模式! console.log(now.utc()); // 时刻<2026-02-19T02:26:29Z>

// 打印格式化字符串 - 请注意它现在使用 UTC 时间 console.log(now.format('MM/DD/YYYY hh:mm:ss a')); // 02/19/2026 02:27:07 上午

关于 Moment 需要记住的关键一点是 Moment 对象始终包含有关时间和日期的信息。如果您只需要使用时间信息,这通常没问题,但在夏令时或闰年等情况下可能会导致意外行为,其中日期可能会影响时间计算。 时间上更加灵活。您可以通过创建 Temporal.Instant 对象来创建表示当前日期和时间的对象。这表示自“纪元”(1970 年 1 月 1 日午夜 UTC)以来的时间定义的时间点。 Temporal 可以以纳秒级的精度参考这一时刻。 const now = Temporal.Now.instant();

// 查看自纪元以来的原始纳秒 console.log(now.epochNanoseconds); // 1771466342612000000n

// UTC 格式 console.log(now.toString()); // 2026-02-19T01:55:27.844Z

// 特定时区的格式 console.log(now.toString({ timeZone: '美国/纽约' })); // 2026-02-18T20:56:57.905-05:00

还可以使用 from 静态方法为特定时间和日期创建 Temporal.Instant 对象。

const myInstant = Temporal.Instant.from('2026-02-18T21:10:00-05:00');

// 设置本地时区的即时格式。请注意,这仅控制 // 格式化 - 它不会像 moment.utc 那样改变对象。 console.log(myInstant.toString({ timeZone: '美国/纽约' })); // 2026-02-18T21:10:00-05:00

您还可以创建其他类型的时间对象,包括:

Temporal.PlainDate:没有时间信息的日期。 Temporal.PlainTime:没有日期信息的时间。 Temporal.ZonedDateTime:特定时区的日期和时间。

其中每个都有一个 from 方法,可以使用指定日期和/或时间的对象或要解析的日期字符串来调用该方法。 // 只是一个日期 const 今天 = Temporal.PlainDate.from({ 年份:2026年, Month: 2, // 注意我们使用 2 表示二月 天:18 }); console.log(today.toString()); // 2026-02-18

// 只是一次 const LunchTime = Temporal.PlainTime.from({ 小时:12 }); console.log(lunchTime.toString()); // 12:00:00

// 美国东部时区的日期和时间 const dueAt = Temporal.ZonedDateTime.from({ 时区: '美国/纽约', 年份:2026年, 月份: 3, 天: 1, 小时: 12, 分钟:0, 第二:0 }); console.log(dueAt.toString()); // 2026-03-01T12:00:00-05:00[美国/纽约]

解析 我们已经介绍了日期和时间信息的编程创建。现在我们来看看解析。解析是 Moment 比内置 Temporal API 更灵活的领域之一。 您可以通过将日期字符串传递给 moment 函数来解析它。对于单个参数,Moment 需要 ISO 日期字符串,但如果您提供第二个参数来指定所使用的日期格式,则可以使用替代格式。

const isoDate = moment('2026-02-21T09:00:00'); const formattedDate = moment('2/21/26 9:00:00', 'M/D/YY h:mm:ss');

控制台.log(isoDate); // 时刻<2026-02-21T09:00:00-05:00>

console.log(格式化日期); // 时刻<2026-02-21T09:00:00-05:00>

在旧版本中,Moment 会做出最佳猜测来解析任何任意格式的日期字符串。这可能会导致不可预测的结果。例如,02-03-2026 是 2 月 2 日还是 3 月 3 日?因此,如果在没有 ISO 格式的日期字符串的情况下调用 Moment,较新版本的 Moment 会显示显着的弃用警告(除非还给出了具有所需格式的第二个参数)。 Temporal 只会解析特定格式的日期字符串。该字符串必须符合 ISO 8601 格式或其扩展 RFC 9557。如果将不符合要求的日期字符串传递给 from 方法,Temporal 将引发 RangeError。

// 使用 RFC 9557 日期字符串 const myDate = Temporal.Instant.from('2026-02-21T09:00:00-05:00[美国/纽约]'); console.log(myDate.toString({ timeZone: '美国/纽约' })); // 2026-02-21T09:00:00-05:00

// 使用未知的日期字符串 const otherDate = Temporal.Instant.from('2/21/26 9:00:00'); // RangeError:时间错误:解析年份值时字符无效。

日期字符串的确切要求取决于您要创建的 Temporal 对象的类型。在上面的示例中,Temporal.Instant 需要完整的 ISO8601 或 RFC 9557 日期字符串指定带有时区偏移的日期和时间,但您也可以仅使用日期格式的子集创建 PlainDate 或 PlainTime 对象。 const myDate = Temporal.PlainDate.from('2026-02-21'); console.log(myDate.toString()); // 2026-02-21

const myTime = Temporal.PlainTime.from('09:00:00'); console.log(myTime.toString()); // 09:00:00

请注意,这些字符串仍然必须符合预期的格式,否则将引发错误。

// 使用不合规的时间字符串。这些都会抛出 RangeError。 Temporal.PlainTime.from('9:00'); Temporal.PlainTime.from('9:00:00 AM');

专业提示:处理非 ISO 字符串因为 Temporal 优先考虑可靠性,所以它不会尝试猜测像 02-01-2026 这样的字符串的格式。如果您的数据源使用此类字符串,则在尝试将其与 Temporal 一起使用之前,您将需要执行一些字符串操作以将值重新排列为 ISO 字符串(例如 2026-02-01)。

格式化 一旦有了 Moment 或 Temporal 对象,您可能希望在某个时候将其转换为格式化字符串。 这是 Moment 更简洁的一个例子。您可以使用描述所需日期格式的标记字符串来调用对象的格式方法。 常量日期 = 时刻();

console.log(date.format('MM/DD/YYYY')); // 2026 年 2 月 22 日

console.log(date.format('MMMM Do YYYY, h:mm:ss a')); // 2026 年 2 月 22 日晚上 8:18:30

另一方面,Temporal 要求您更详细一些。临时对象(例如 Instant)具有 toLocaleString 方法,该方法接受指定为对象属性的各种格式选项。

const 日期 = Temporal.Now.instant();

// 不带参数,我们将获得当前语言环境的默认格式 console.log(date.toLocaleString()); // 2/22/2026, 8:23:36 PM(假设区域设置为 en-US)

// 传递格式化选项以生成自定义格式字符串 console.log(date.toLocaleString('en-US', { 月份:“长”, 日:'数字', 年份:'数字', 小时:'2 位数字', 分钟:“2 位数字” })); // 2026 年 2 月 22 日晚上 8:23

// 只在格式字符串中传递你想要的字段 console.log(date.toLocaleString('en-US', { 月份:“短”, 日:'数字' })); // 2 月 22 日

临时日期格式化实际上在底层使用了 Intl.DateTimeFormat API(现代浏览器中已经可以使用)。这意味着您可以使用自定义格式选项创建可重用的 DateTimeFormat 对象,然后将 Temporal 对象传递给其格式方法。因此,它不支持像 Moment 那样的自定义日期格式。如果您需要“2026 年第一季度”或其他特殊格式,您可能需要一些自定义日期格式代码或访问第三方库。 const 格式化程序 = new Intl.DateTimeFormat('en-US', { 月份:'2 位数字', 日:'2 位数字', 年份:'数字' });

const 日期 = Temporal.Now.instant(); console.log(formatter.format(日期)); // 2026 年 2 月 22 日

Moment 的格式化标记编写起来更简单,但它们不适合区域设置。格式字符串“硬编码”诸如月/日顺序之类的东西。像 Temporal 一样,使用配置对象的优点是它会自动适应任何给定的语言环境并使用正确的格式。 const 日期 = Temporal.Now.instant();

const 格式选项 = { 月份:'数字', 日:'数字', 年份:'数字' };

console.log(date.toLocaleString('en-US', formatOptions)); // 2026 年 2 月 22 日

console.log(date.toLocaleString('en-GB', formatOptions)); // 2026 年 2 月 22 日

日期计算 在许多应用程序中,您最终需要对日期执行一些计算。您可能需要添加或减去时间单位(天、小时、秒等)。例如,如果您有当前日期,您可能希望向用户显示 1 周后的日期。 Moment 对象具有执行这些操作的加法和减法等方法。这些函数采用一个值和一个单位,例如:add(7, 'days')。然而,Moment 和 Temporal 之间的一个非常重要的区别是,在执行这些日期计算时,底层对象会被修改,并且其原始值会丢失。 const now = moment();

控制台.log(现在); // 时刻<2026-02-24T20:08:36-05:00>

const nextWeek = now.add(7, '天'); 控制台.log(下周); // 时刻<2026-03-03T20:08:36-05:00>

// 问题 - 原始对象已发生突变 控制台.log(现在); // 时刻<2026-03-03T20:08:36-05:00>

为了避免丢失原始日期,您可以对Moment对象调用clone来创建一个副本。 现在常量=时刻(); const nextWeek = now.clone().add(7, '天');

控制台.log(现在); // 时刻<2026-02-24T20:12:55-05:00>

控制台.log(下周); // 时刻<2026-03-03T20:12:55-05:00>

另一方面,时间对象是不可变的。一旦创建了 Instant、PlainDate 等对象,该对象的值就永远不会改变。时间对象也有加法和减法方法。 Temporal 对于可以将哪些时间单位添加到哪些对象类型有点挑剔。例如,您不能向 Instant 添加天数:

const now = Temporal.Now.instant(); const nextWeek = now.add({ 天数: 7 }); // RangeError:时间错误:最大单位不能是日期单位

这是因为 Instant 对象代表 UTC 中的特定时间点并且与日历无关。由于一天的长度可能会根据时区规则(例如夏令时)而变化,因此此计算在 Instant 上不可用。但是,您可以对其他类型的对象执行此操作,例如 PlainDateTime: const now = Temporal.Now.plainDateTimeISO(); console.log(now.toLocaleString()); // 2026 年 2 月 24 日晚上 8:23:59

const nextWeek = now.add({ 天数: 7 });

// 注意原来的PlainDateTime保持不变 console.log(now.toLocaleString()); // 2026 年 2 月 24 日晚上 8:23:59

console.log(nextWeek.toLocaleString()); // 2026 年 3 月 3 日晚上 8:23:59

您还可以计算两个 Moment 或 Temporal 对象之间的时间间隔。 使用 Moment 的 diff 函数,您需要提供粒度单位,否则它将返回以毫秒为单位的差异。 const date1 = moment('2026-02-21T09:00:00'); const date2 = moment('2026-02-22T10:30:00');

console.log(date2.diff(date1)); // 91800000

console.log(date2.diff(date1, '天')); // 1

要使用 Temporal 对象执行此操作,您可以将另一个 Temporal 对象传递给其 Until 或 Since 方法。这将返回一个 Temporal.Duration 对象,其中包含有关时间差的信息。 Duration 对象具有差异的每个组成部分的属性,并且还可以生成表示时间差的 ISO 8601 持续时间字符串。

const date1 = Temporal.PlainDateTime.from('2026-02-21T09:00:00'); const date2 = Temporal.PlainDateTime.from('2026-02-22T10:30:00');

//largestUnit指定最大的时间单位来表示 // 在持续时间计算中 const diff = date2.since(date1, {largeUnit: '天' });

console.log(diff.days); // 1

console.log(diff.hours); // 1

console.log(diff.分钟); // 30

console.log(diff.toString()); // P1DT1H30M //(ISO 8601 持续时间字符串:1 天、1 小时、30 分钟)

比较日期和时间 Moment 和 Temporal 都可以让您比较日期和时间,以确定哪个在另一个之前,但对 API 采取不同的方法。 Moment 提供了 isBefore、isAfter 和 isSame 等方法来比较两个 Moment 对象。 const date1 = moment('2026-02-21T09:00:00'); const date2 = moment('2026-02-22T10:30:00');

console.log(date1.isBefore(date2)); // 正确

Temporal 使用静态比较方法来执行相同类型的两个对象之间的比较。如果第一个日期早于第二个日期,则返回 -1;如果它们相等,则返回 0;如果第一个日期晚于第二个日期,则返回 1。以下示例演示如何比较两个 PlainDate 对象。 Temporal.PlainDate.compare 的两个参数都必须是 PlainDate 对象。

const date1 = Temporal.PlainDate.from({ 年:2026 年,月:2,日:24 }); const date2 = Temporal.PlainDate.from({ 年:2026 年,月:3,日:24 });

// date1 在 date2 之前,所以 -1 console.log(Temporal.PlainDate.compare(date1, date2));

// 如果我们尝试比较两个不同类型的对象,则会出错 console.log(Temporal.PlainDate.compare(date1, Temporal.Now.instant())); // TypeError:时间错误:提供的 PlainDate 字段无效。

特别是,这使得按时间顺序对 Temporal 对象数组进行排序变得很容易。 // Temporal.PlainDate 对象的数组 常量日期 = [ ... ];

// 使用 Temporal.PlainDate.compare 作为比较器函数 日期.排序(Temporal.PlainDate.compare);

时区换算 核心 Moment 库不支持时区转换。如果需要此功能,还需要安装 moment-timezone 包。该包不可进行树摇动,因此会显着增加您的包大小。安装 moment-timezone 后,您可以使用 tz 方法将 Moment 对象转换为不同的时区。与其他 Moment 操作一样,这会改变底层目的。 // 假设美国东部时间 const now = moment(); 控制台.log(现在); // 时刻<2026-02-28T20:08:20-05:00>

// 转换为太平洋时间。 // 原始东部时间丢失。 now.tz('美国/洛杉矶'); 控制台.log(现在); // 时刻<2026-02-28T17:08:20-08:00>

使用 Temporal.ZonedDateTime 对象时,时区功能内置于 Temporal API 中。这些对象包括一个 withTimeZone 方法,该方法返回一个新的 ZonedDateTime ,表示同一时刻,但在指定的时区。 // 再次假设美国东部时间 const now = Temporal.Now.zonedDateTimeISO(); console.log(now.toLocaleString()); // 美国东部时间 2026 年 2 月 28 日晚上 8:12:02

// 转换为太平洋时间 const nowPacific = now.withTimeZone('美国/洛杉矶'); console.log(nowPacific.toLocaleString()); // 2026 年 2 月 28 日下午 5:12:02(太平洋标准时间)

// 原始对象保持不变 console.log(now.toLocaleString()); // 美国东部时间 2026 年 2 月 28 日晚上 8:12:02

注意:toLocaleString 返回的格式化值,顾名思义,与区域设置相关。示例代码是在 en-US 语言环境中开发的,因此格式如下:2/28/2026, 5:12:02 PM PST。在另一个区域设置中,这可能有所不同。例如,在 en-GB 区域设置中,您会得到类似 28/2/2026, 17:12:02 GMT-8 的信息。 现实世界的重构 假设我们正在构建一个用于跨时区安排活动的应用程序。此应用程序的一部分是一个函数 getEventTimes,它采用表示事件的时间和日期、本地时区和目标时区的 ISO 8601 字符串。该函数为两个时区的事件创建格式化的时间和日期字符串。 如果函数给出的输入字符串不是有效的时间/日期字符串,它将抛出错误。 这是使用 Moment 的原始实现(还需要使用 moment-timezone 包)。

从“时刻时区”导入时刻;

函数 getEventTimes(inputString, userTimeZone, targetTimeZone) { const timeFormat = 'MMM D, YYYY, h:mm:ss a z';

// 1. 创建用户所在时区的初始时刻 const eventTime = moment.tz( 输入字符串, moment.ISO_8601, // 期望 ISO 8601 字符串 true, // 严格解析 用户时区 );

// 如果输入字符串不代表有效日期,则抛出错误 if (!eventTime.isValid()) { throw new Error('无效的日期/时间输入'); }

// 2.计算目标时间 // 关键:我们必须克隆,否则“eventTime”将永远改变! const targetTime = eventTime.clone().tz(targetTimeZone);

返回{ 本地:eventTime.format(timeFormat), 目标:targetTime.format(timeFormat), }; }

常量日程 = getEventTimes( '2026-03-05T15:00-05:00', '美国/纽约', '欧洲/伦敦', );

console.log(schedule.local); // 美国东部时间 2026 年 3 月 5 日下午 3:00:00

console.log(schedule.target); // 格林威治标准时间 2026 年 3 月 5 日晚上 8:00:00

在此示例中,我们使用 ISO 8601 的预期日期格式,该格式内置于 Moment 中,非常有用。我们还使用严格的解析,这意味着 Moment 不会尝试猜测与格式不匹配的日期字符串。如果传递非 ISO 日期字符串,将导致无效的日期对象,并且我们会抛出错误。 Temporal 实现看起来很相似,但有一些关键区别。

函数 getEventTimes(inputString, userTimeZone, targetTimeZone) { // 1.将输入直接解析成Instant,然后创建 // 用户区域中的 ZonedDateTime。 const instant = Temporal.Instant.from(inputString); const eventTime = instant.toZonedDateTimeISO(userTimeZone);

// 2. 转换到目标区域 // 这会自动返回一个新对象; “eventTime”是安全的。 const targetTime = eventTime.withTimeZone(targetTimeZone);

// 3. 使用 Intl 格式化(内置) 常量选项 = { 年份:'数字', 月份:“短”, 日:'数字', 小时:'数字', 分钟:'2 位数字', 第二个:“2 位数字”, 时区名称:'短' };

返回{ 本地: eventTime.toLocaleString(navigator.language, options), 目标:targetTime.toLocaleString(navigator.语言,选项) }; }

常量日程 = getEventTimes( '2026-03-05T15:00-05:00', '美国/纽约', '欧洲/伦敦', );

console.log(schedule.local); // 美国东部时间 2026 年 3 月 5 日下午 3:00:00

console.log(schedule.target); // 格林威治标准时间 2026 年 3 月 5 日晚上 8:00:00

对于 Moment,我们必须为结果日期字符串显式指定格式字符串。无论用户的位置或区域设置如何,事件时间的格式将始终为 Mar 5, 2026, 3:00:00美国东部时间下午。 此外,我们不必显式抛出异常。如果将无效字符串传递给 Temporal.Instant.from,Temporal 将为我们抛出异常。需要注意的一点是,即使进行了严格的解析,Moment 版本仍然更加宽松。时间需要字符串末尾的时区偏移量。 您还应该注意,由于我们使用的是 navigator.language,因此该代码只能在浏览器环境中运行,因为 navigator 不是在 Node.js 环境中定义的。 Temporal 实现使用浏览器的当前区域设置 (navigator.language),因此用户将自动获取采用本地时间格式的事件时间。在 en-US 语言环境中,时间为 2026 年 3 月 5 日下午 3:00:00(美国东部时间)。但是,例如,如果用户位于伦敦,则事件时间将被格式化为 2026 年 3 月 5 日,15:00:00 GMT-5。 总结

行动 Moment.js 颞叶 当前时间 时刻() Temporal.Now.zonedDateTimeISO() 解析ISO 力矩(str) Temporal.Instant.from(str) 添加时间 .add(7, 'days') (变异) .add({ days: 7 }) (新对象) 差异 .diff(其他, '小时') .自(其他).小时 时区 .tz('区域/名称') .withTimeZone('区域/名称')

乍一看,语法上的差异可能略有不同(对于 Temporal,有时更详细、更严格),但与 Moment.js 相比,使用 Temporal 有几个关键优势:

更明确意味着更少的意外和意外错误。 Moment 可能看起来更宽松,但它涉及“猜测”,有时会导致日期不正确。如果你给 Temporal 一些无效的东西,它会抛出一个错误。如果代码运行,您就知道您已经获得了有效的日期。 Moment 可以显着增加应用程序包的大小,特别是当您使用 moment-timezone 包时。 Temporal 不会添加任何内容(一旦它在您的目标浏览器中发布)。 不变性让您确信在执行日期转换和操作时永远不会丢失或覆盖数据。 根据您的要求,时间的不同表示形式(Instant、PlainDateTime、ZonedDateTime),其中 Moment 始终是 UTC 时间戳的包装。 Temporal 使用 Intl API 进行日期格式设置,这意味着您无需显式指定标记即可进行区域设置感知格式设置。

关于 Polyfill 的注释 如前所述,有一个 Temporal polyfill 可用,作为名为 @js-temporal/polyfill 的 npm 包分发。如果您今天想使用 Temporal,您将需要这个 polyfill 来支持 Safari 等尚未提供 API 的浏览器。坏消息是它会增加你的包大小。好消息是它的增加量仍然明显少于 moment 或 moment-timezone。以下是 Bundlephobia.com 报告的包大小比较,该网站提供有关 npm 包大小的信息(单击每个包名称即可查看 Bundlephobia 分析):

套餐 缩小版 缩小并压缩 @js-temporal/polyfill 154.1 KB 44.1 KB 时刻 294.4 KB 75.4 KB 时刻时区 1MB 114.2 KB

Polyfill 历史上也存在一些与内存使用相关的性能问题,在撰写本文时,它被认为处于 alpha 状态。因此,在它达到更成熟的状态之前,您可能不想在生产中使用它。 另一个好消息是,希望 Polyfill 不会被需要太久(当然,除非您需要支持较旧的浏览器)。截至撰写本文时,Temporal 已在 Chrome、Edge 和 Firefox 中发布。它在 Safari 中还没有完全准备好,尽管它似乎可以在最新的技术预览中使用运行时标志。

You May Also Like

Enjoyed This Article?

Get weekly tips on growing your audience and monetizing your content — straight to your inbox.

No spam. Join 138,000+ creators. Unsubscribe anytime.

Create Your Free Bio Page

Join 138,000+ creators on Seemless.

Get Started Free