跳转到内容

通知 · API

Notification 接口

发布于

Notification 是代表一条已显示通知的对象。new Notification(title, options) 从页面或专用 worker 创建并立即显示一条非持久通知;同一个接口在持久通知的场景下以 event.notification 交给 Service Worker。它的实例属性映射创建时传入的选项,事件则报告显示、激活、关闭和失败。

new Notification(title)
new Notification(title, options)
notification.close()
Notification.permission
Notification.maxActions

构造函数暴露在 Window 以及专用和共享 worker 上,在 ServiceWorkerGlobalScope 内抛出,那里的替代是 self.registration.showNotification()。桌面端支持为 Chrome 20、Firefox 22、Safari 7、Edge 14(BCD api.Notification.Notification)。移动端构造函数虽然存在,但在 Chrome for Android、Samsung Internet 和 iOS 上的 Safari 中无法使用(细节见「异常」),所以 PWA 把它当作仅限桌面的便利。

实例成员均为只读,映射构造函数的 options。

成员 类型 含义
title、body、icon、image、badge string 创建时传入的文本与图片 URL。缺省的选项读作 ""。
tag string 替换键。同一源上后来带相同 tag 的通知会替换这一条。
data any 作为 options.data 传入的可结构化克隆载荷;没有时为 null。
dir、lang string 文字方向("auto"、"ltr"、"rtl")与 BCP 47 语言标签。
requireInteraction、renotify、silent boolean(silent 可为 null) 行为标志;各引擎支持情况见 Notifications API 的参数表。
timestamp number 通知所关联的时间,自纪元起的毫秒数;默认为创建时间。
vibrate 数字数组 振动模式,Android 上的 Chromium。
actions array 非持久通知上恒为空数组;Service Worker 内的 event.notification 上有内容。
navigate string 激活时打开的 URL,Safari 18.4。

事件有 show(已显示;iOS 上的 Safari 不触发)、click、close 与 error(显示失败,例如权限在检查与调用之间被撤销)。静态的 Notification.permission 见 Notification.requestPermission();Notification.maxActions 返回引擎会显示的操作按钮数量,在 Chromium 中为 2(notification.mojom 中的 kMaximumActions,chromium.googlesource.com),在 Safari 中为 undefined,因为该静态成员不存在。

异常 触发条件
TypeError 在 Service Worker 内调用构造函数。Chromium 的报错文本为 Illegal constructor. Use ServiceWorkerRegistration.showNotification() instead.(notification.cc,chromium.googlesource.com)。
TypeError 在 Chrome for Android 或 Samsung Internet 中从任何上下文调用构造函数;BCD 记录该构造函数在那里总是抛出(api.Notification.Notification,chrome_android)。报错文本就是同一句 Illegal constructor。
TypeError options.actions 非空。Chromium 的报错文本为 Actions are only supported for persistent notifications shown using ServiceWorkerRegistration.showNotification().。
TypeError renotify 为 true 但 tag 为空,或 silent 为 true 同时设置了 vibrate。
ReferenceError iOS 与 iPadOS 上 Safari 的浏览器标签页:除非页面是 manifest 带非默认 display 的主屏幕 Web App,否则 Notification 标识符不存在。

权限被拒或未决定不是异常。构造函数返回一个 Notification,其 error 事件触发而什么都不显示,这就是调用前要检查 Notification.permission 的原因。

该接口在桌面端普遍存在,在移动端要么缺失、要么没有可用的构造函数:Chrome for Android 42 与 Samsung Internet 4 只为 Service Worker 用途暴露它,iOS 上的 Safari 16.4 只在已安装的 Web App 内暴露它,Android WebView 没有(BCD api.Notification)。Chrome 自 49 起不在无痕模式显示通知。接口存在的地方实例成员和事件都受支持,但 iOS 上没有 show,而 actions、badge、image、renotify、timestamp 与 vibrate 仅限 Chromium。

第一个示例天然只适用于桌面;第二和第三个是在 Android 和 iOS 上同样可用的形态。

权限已授予时,构造函数立即显示。click 处理函数聚焦窗口并关闭通知;不调用 close() 的话,操作系统会保留它直到自己的超时。

function showOrderUpdate(orderId) {
const notification = new Notification('订单已发货', {
body: `订单 #${orderId} 正在路上。`,
icon: '/icons/parcel.png',
tag: `order-${orderId}`,
data: { orderId },
});
notification.addEventListener('click', () => {
window.focus();
location.hash = `#order-${notification.data.orderId}`;
notification.close();
});
notification.addEventListener('error', () => console.warn('通知未显示'));
}

浏览器在显示几秒后自行关闭非持久通知,并把它排除在通知中心之外,所以这种形态适合「已保存」之类的确认,而不适合用户会回头查看的消息。

在 notificationclick 处理函数里,同一个接口以 event.notification 到达,此时 actions 有内容且 close() 可用。

self.addEventListener('notificationclick', (event) => {
const { tag, data, actions } = event.notification;
event.notification.close();
if (event.action === 'archive') {
event.waitUntil(fetch(`/api/threads/${data.threadId}/archive`, { method: 'POST' }));
return;
}
event.waitUntil(self.clients.openWindow(`/inbox#${tag}`));
});

这里的 actions.length 至多为 Notification.maxActions;超出该上限的按钮在显示通知时已被静默丢弃。

可靠的探测是在确认接口与权限之后,在 try 里构造。任何失败都转到持久路径,而它在 Android 和 iOS 上也是唯一的路径。

async function show(title, options) {
if (!('Notification' in window) || Notification.permission !== 'granted') {
return showInPage(title, options.body); // 没有接口,或没有权限
}
try {
return new Notification(title, options);
} catch (err) {
if (err.name !== 'TypeError') throw err;
const registration = await navigator.serviceWorker.getRegistration();
if (!registration?.active) return showInPage(title, options.body); // 没有可退回的对象
return registration.showNotification(title, options);
}
}

生产代码通常完全跳过构造函数,在桌面和移动端都调用 showNotification();这个探测在没有注册 Service Worker 的场合才有用。

规范

规范状态
无。