浏览器通知是怎么做到的?前端实现桌面消息提醒
浏览器通知是怎么做到的?前端实现桌面消息提醒
最近看到一些网站在收到新消息时,会在电脑右下角弹出类似系统通知的提醒。比如论坛有新回复、私信、帖子更新时,即使当前页面不在前台,也能看到 Chrome 推出的通知。
很多前端同学第一反应可能是:这是网页里写了一个 fixed 弹窗吗?
其实不是。
这种通知通常是 浏览器原生通知能力。网站拿到用户授权后,通过浏览器的 Notification API 或 Push API,让 Chrome 把消息交给操作系统通知中心展示。
它不是普通弹窗
普通网页弹窗一般是 DOM 元素,比如:
<div class="toast">你有一条新消息</div>
这种弹窗只能显示在网页内部,页面关闭或切到别的软件后,用户就看不到了。
而浏览器通知是系统级展示:
new Notification('你有一条新消息', {
body: '有人回复了你的帖子',
icon: '/logo.png'
})
它的样式、位置、关闭按钮都由浏览器和操作系统控制,前端不能像 CSS 那样自由修改。
前端实现分两种情况
第一种是页面还开着,只是用户切到了后台。
这种情况比较简单,前端拿到新消息后直接调用 new Notification() 就可以。
第二种是页面已经关闭了,用户仍然能收到通知。
这种就需要 Service Worker + Push API + 后端推送。前端负责订阅推送并注册 Service Worker,后端负责真正把消息推给浏览器。
页面打开时的实现
先判断浏览器是否支持通知:
function supportNotification() {
return 'Notification' in window
}
然后通过用户点击申请通知权限:
async function requestNotifyPermission() {
if (!supportNotification()) return false
const permission = await Notification.requestPermission()
return permission === 'granted'
}
注意,权限申请最好放在“开启通知”按钮点击后触发,不建议页面一加载就申请。很多浏览器会拦截这种没有用户行为触发的权限请求。
收到新消息后,可以这样弹通知:
function showNotify(message) {
if (!supportNotification()) return
if (Notification.permission !== 'granted') return
const notice = new Notification(message.title, {
body: message.body,
icon: message.icon || '/logo.png',
tag: message.tag || message.id
})
notice.onclick = () => {
window.focus()
if (message.url) {
window.location.href = message.url
}
notice.close()
}
}
如果项目里有 WebSocket,可以在收到消息时调用:
socket.onmessage = event => {
const data = JSON.parse(event.data)
if (document.hidden) {
showNotify({
id: data.id,
title: data.title,
body: data.content,
icon: data.avatar,
url: `/message/${data.id}`,
tag: `message-${data.id}`
})
}
}
这里用 document.hidden 判断页面是否在后台。这样可以避免用户正在看页面时,系统通知还一直弹出来,体验会更自然。
页面关闭后也能收到通知
如果希望用户关掉页面后仍然收到消息,就不能只靠 new Notification() 了。
这时候要注册 Service Worker:
const registration = await navigator.serviceWorker.register('/sw.js')
然后订阅 Push:
const subscription = await registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: vapidPublicKey
})
再把订阅信息传给后端保存:
await fetch('/api/push-subscription', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(subscription)
})
Service Worker 里监听推送消息:
self.addEventListener('push', event => {
const data = event.data.json()
event.waitUntil(
self.registration.showNotification(data.title, {
body: data.body,
icon: data.icon || '/logo.png',
tag: data.tag,
data: {
url: data.url
}
})
)
})
点击通知后打开对应页面:
self.addEventListener('notificationclick', event => {
event.notification.close()
const url = event.notification.data?.url || '/'
event.waitUntil(
clients.openWindow(url)
)
})
前端需要注意的点
浏览器通知必须在 HTTPS 环境下使用,本地 localhost 例外。
通知权限只能由用户授权,前端不能静默开启。
通知样式不能完全自定义,前端主要能控制标题、内容、图标、跳转地址、去重标识等字段。
如果只是页面打开时提醒,用 Notification API + WebSocket 就够了。
如果页面关闭后也要提醒,就必须接入 Service Worker + Push API + 后端推送服务。
总结
网页右下角这种系统通知,本质上是浏览器提供的原生能力。
前端要做的事情主要有三步:
- 引导用户开启通知权限
- 在收到新消息时判断是否需要弹通知
- 根据业务场景选择普通 Notification 或 Service Worker Push
对于论坛、聊天、工单、邮箱这类系统来说,浏览器通知是一个很实用的功能。它不复杂,但要注意权限、兼容性和用户体验。尤其是不要滥用通知,否则用户很容易直接把网站通知权限关掉。
本文来自博客园,作者:jialiangzai,转载请注明原文链接:https://www.cnblogs.com/zsnhweb/p/21037575

浙公网安备 33010602011771号