# Notification 接口：构造并读取单条通知

> Notification() 构造函数及其选项（body、icon、tag、data、requireInteraction）、click/close/error 事件，以及根据 MDN，为何直接调用它在几乎所有移动端浏览器上会抛出 TypeError。

**一句话：** `Notification` 是单条已显示通知背后的接口——`new Notification(title,
options)` 会从页面创建并立即显示一条通知，它的只读属性（`title`、`body`、`data` 等）
镜像了构造时传入的选项，并且会触发 `click`、`close`、`error` 事件供你监听。

## 构造一条通知

```js
if ('Notification' in window && Notification.permission === 'granted') {
  const n = new Notification('订单已发货', {
    body: '你的订单 #1234 正在配送途中。',
    icon: '/icons/parcel.png',
    tag: 'order-1234',
    data: { orderId: '1234' },
  });

  n.addEventListener('click', () => {
    window.focus();
    n.close();
  });
}
```

根据 MDN，构造前应先用 `Notification.requestPermission()` 获取权限——完整的权限流程见
[Notifications API 一节](/zh/reference/notifications/notifications-api/)。

## 关键构造选项

- **`body`** —— 显示在标题下方的次要文本。
- **`icon`** —— 随通知显示的图标图片 URL。
- **`tag`** —— 根据 MDN，通知的标识字符串；可与 `renotify`（要求非空 `tag`）配合，在
  替换时再次提醒用户。
- **`data`** —— 根据 MDN，任意结构化可克隆数据，通过 `notification.data` 读回。
- **`requireInteraction`** —— 一个布尔值；根据 MDN，为 `true` 时通知会保持显示，直到
  用户与其交互或将其关闭，而不是自动关闭。

## 事件

- **`click`** —— 用户点击通知时触发。
- **`close`** —— 根据 MDN，用户关闭通知时触发。
- **`error`** —— 通知显示出错时触发。

## 移动端的限制：改用 service worker

根据 MDN，直接调用 `Notification()` 构造函数在**几乎所有移动端浏览器上都会抛出
`TypeError`**，因为在移动端，页面脚本通常不会在后台运行——而这恰恰是通知本应触达的场景。
移动端安全的做法是注册一个 service worker，改为调用
`ServiceWorkerRegistration.showNotification()`，它支持相同的选项，还额外支持操作按钮，并
且无需打开页面即可工作：

```js
async function notifyFromServiceWorker(title, options) {
  if (
    !('serviceWorker' in navigator) ||
    !('Notification' in window) ||
    Notification.permission !== 'granted'
  ) {
    // 回退：不支持 service worker、没有 Notification API，或没有权限——
    // 什么都不做，而不是调用构造函数冒着移动端 TypeError 的风险。
    return;
  }
  const registration = await navigator.serviceWorker.ready;
  if (typeof registration.showNotification !== 'function') {
    // 回退：registration 已存在，但 showNotification 不可用——
    // 没有移动端安全的 API 可用，不做更多操作。
    return;
  }
  await registration.showNotification(title, options);
}
```

关于这一点如何应用于 push 投递的通知，参见
[Web Push](/zh/reference/notifications/web-push/) 与
[iOS 与 Safari 上的 Web Push](/zh/reference/notifications/ios-safari-push/)。

## 浏览器与生态支持

根据 MDN，`Notification` 属于**有限可用**，尚未进入 Baseline，因为它在部分主流浏览器中
表现并不一致——上文提到的移动端构造函数 `TypeError` 就是这种缺口的一个例子。更全面的
按平台权限与可用性说明参见
[Notifications API](/zh/reference/notifications/notifications-api/)。

## 实践清单

- [ ] 根据 MDN，构造前调用 `Notification.requestPermission()` 并检查是否为 `granted`。
- [ ] 为相关通知设置 `tag`，需要在替换时再次提醒用户时配合 `renotify`。
- [ ] 在 `click` 处理器中读取 `notification.data`，获取通知需要处理的负载。
- [ ] 若不希望通知一直停留，点击时自行调用 `notification.close()`。
- [ ] 在移动端，或任何需要 push 驱动通知的场景下，改用
      `ServiceWorkerRegistration.showNotification()` 而非页面构造函数。

## 相关参考

- [Notifications API](/zh/reference/notifications/notifications-api/)
- [Web Push](/zh/reference/notifications/web-push/)