# 通知的 actions 与 badge 选项

> showNotification() 的 actions 与 badge 选项：各字段、Chromium 以 Notification.maxActions 暴露的两个按钮上限、96 × 96 的 badge 图片与引擎支持。

`actions` 给持久通知添加按钮，`badge` 提供完整通知放不下时操作系统显示的小型单色图片，例如 Android 状态栏。两者都是 `ServiceWorkerRegistration.showNotification()` 的 `options` 字典成员；在已发布的浏览器中，除了 Firefox 152 的 `actions` 之外都仅限 Chromium；两者都与 Badging API 设置的应用图标计数无关。

## 语法

```js
registration.showNotification(title, {
  badge: '/icons/badge-96.png',
  actions: [{ action: 'reply', title: '回复', icon: '/icons/reply.png' }],
})
Notification.maxActions
```

`actions` 只被 `showNotification()` 接受；向 `new Notification()` 传入非空数组会抛出 `TypeError`。`Notification.maxActions` 是静态 getter，返回引擎显示的按钮数量。支持情况：`actions` 在 Chrome 53、Edge 18、Firefox 152；`badge` 在 Chrome 53、Edge 18；Safari 两者都不支持（BCD `api.Notification.actions`、`api.Notification.badge`）。

## 成员

| 成员 | 类型 | 含义 |
|---|---|---|
| `actions[].action` | string | 在 `notificationclick` 中以 `event.action` 返回的标识符。必填。 |
| `actions[].title` | string | 按钮文字。必填。 |
| `actions[].icon` | string（URL），可选 | 在绘制图标的平台（Android；Windows 不绘制）上显示在按钮上的图片。 |
| `actions[].navigate` | string（URL），可选 | Safari 18.4：打开该 URL 而不触发 `notificationclick`。Chromium 忽略它。 |
| `badge` | string（URL） | 紧凑形态使用的图片。Android 会把它遮罩成剪影并以最高 4 倍密度显示，因此带透明背景的 96 × 96 像素单色 PNG 是可用的尺寸。 |

Chromium 最多显示 `kMaximumActions = 2` 个按钮（[notification.mojom](https://chromium.googlesource.com/chromium/src/+/main/third_party/blink/public/mojom/notifications/notification.mojom)，chromium.googlesource.com），多余的不报错直接丢弃；Firefox 152 通过 `maxActions` 报告自己的上限。读取这个 getter，不要把 2 写死。

## 异常

| 异常 | 触发条件 |
|---|---|
| `TypeError` | `new Notification()` 上的 `actions` 非空。Chromium：`Actions are only supported for persistent notifications shown using ServiceWorkerRegistration.showNotification().` |
| `TypeError` | 某个 action 对象缺少 `action` 或 `title`，这两个是必填的字典成员。 |

不支持的选项不是异常：Firefox 152 之前的版本和 Safari 忽略 `actions`，Chromium 之外的所有引擎忽略 `badge`，通知只带正文显示。

## 支持位置

`actions` 与 `badge` 在 Chrome 53（2016 年）一起发布，并随 Edge 转向 Chromium 到达 Edge；Firefox 在 152 加入了 `actions` 但仍忽略 `badge`；Safari 在 macOS 和 iOS 上两者都不支持，通知按钮不属于其 Web 通知界面（BCD `api.Notification.actions`、`api.Notification.badge`）。在 Android 上 badge 显示在状态栏和锁屏上；在 Windows 和 macOS 上 Chromium 忽略 `badge`，因为操作系统没有紧凑形态的位置。

## 示例

示例把页面侧的 `showNotification()` 调用与读取 `event.action` 的 Service Worker 处理函数配对。

### 两个按钮，各自一个处理分支

Service Worker 读取 `event.action`。空字符串表示点的是通知主体，其他值是某个 `action` id。

```js
// 页面
await registration.showNotification('Ada 发来新消息', {
  body: '能把电话改到下午 3 点吗？',
  badge: '/icons/badge-96.png',
  tag: 'thread-42',
  data: { threadId: 42 },
  actions: [
    { action: 'reply', title: '回复' },
    { action: 'mute', title: '静音此会话' },
  ],
});

// Service Worker
self.addEventListener('notificationclick', (event) => {
  event.notification.close();
  const { threadId } = event.notification.data;
  if (event.action === 'mute') {
    event.waitUntil(fetch(`/api/threads/${threadId}/mute`, { method: 'POST' }));
  } else {
    event.waitUntil(self.clients.openWindow(`/threads/${threadId}${event.action === 'reply' ? '#compose' : ''}`));
  }
});
```

Chromium 的上限是两个，所以按「主要操作、破坏性操作」的顺序放；第三个按钮会被丢弃。

### 为 badge 图片定尺寸

badge 以剪影方式绘制：每个不透明像素都变成白色（或系统强调色），带内部细节的 logo 会变成一团。导出一个 96 × 96 像素、透明背景的单色图形。

```js
await registration.showNotification('下载完成', {
  body: 'report-2026-q3.pdf',
  icon: '/icons/icon-192.png',   // 全彩，显示在文字旁
  badge: '/icons/badge-96.png',  // 单色，显示在状态栏
});
```

`icon` 与 `badge` 服务于不同的位置，两者都值得设置；只有 `icon` 的通知在 Android 状态栏里显示的是浏览器自己的图标。

### 检测选项并在不支持处省略它们

支持这些选项的地方，它们是 `Notification.prototype` 的属性。按条件构建选项对象，同一个调用就能在 Safari 和 Firefox 里工作。

```js
function notificationOptions(base, buttons) {
  if (!('Notification' in window)) return null; // 完全没有通知
  const options = { ...base };
  if ('badge' in Notification.prototype) options.badge = '/icons/badge-96.png';
  if ('actions' in Notification.prototype && Notification.maxActions > 0) {
    options.actions = buttons.slice(0, Notification.maxActions);
  }
  return options;
}
```

按 `maxActions` 截取保留的是前几个按钮，而不是让引擎随意丢掉后面的；当数组顺序是「主要、次要、破坏性」时这一点很重要。

:::observed
`Notification.maxActions` 在 Windows、macOS 和 Android 上的 Chrome 与 Edge 中都返回 `2`，即 Chromium [notification.mojom](https://chromium.googlesource.com/chromium/src/+/main/third_party/blink/public/mojom/notifications/notification.mojom)（chromium.googlesource.com）中的常量 `kMaximumActions = 2`；在 Safari 18 中返回 `undefined`，那里既没有该静态成员，`'actions' in Notification.prototype` 也为 `false`。在 Chrome 中向 `showNotification()` 传入三个 action 只显示前两个，Console 没有任何警告；向 `new Notification()` 传入一个则抛出 `TypeError: Failed to construct 'Notification': Actions are only supported for persistent notifications shown using ServiceWorkerRegistration.showNotification().`。
:::

## 另请参阅

- [Notifications API Standard: actions](https://notifications.spec.whatwg.org/#dom-notification-actions)（whatwg.org）
- [Notification: actions property](https://developer.mozilla.org/en-US/docs/Web/API/Notification/actions)（developer.mozilla.org）
- [Notifications API](/zh/reference/notifications/notifications-api/)
- [Notification 接口](/zh/reference/notifications/notification/)
- [Badging API](/zh/reference/installation/badging/)