---
tags: Javascript
---
# Notifications API瀏覽器通知
## 通知 API
[Notifications API](https://developer.mozilla.org/en-US/docs/Web/API/Notifications_API)允許我們向用戶顯示通知。 它非常強大且易於使用。在可能的情況下,它使用與原生應用程序相同的機制,提供完全原生的外觀和感覺。
我們可以將 `Notifications API` 分成兩個核心區域(這些是非技術性的,也不屬於規範的一部分)。調用API (**Invocation API**) 控制如何使您的通知出現,包括樣式和振動。我們從頁面(或從服務器,在推送通知的情況下)創建(或調用)通知。交互 API 控制用戶與通知互動時發生的情況。 用戶交互在 service worker 中處理。
### 請求許可
在創建通知之前,我們需要獲得用戶的許可。放在主JS文件中
```javascript=
Notification.requestPermission(function(status) {
console.log('Notification permission status:', status);
});
```
### 顯示通知
可以使用`showNotification`方法(“調用 API”)顯示來自應用程序主腳本的通知 。這是一個例子:
```javascript=
function displayNotification() {
if (Notification.permission == 'granted') {
navigator.serviceWorker.getRegistration().then(function(reg) {
reg.showNotification('Hello world!');
});
}
}
```
#### 通知選項
`showNotification`方法有一個可選的第二個參數來配置通知。
```javascript=
function displayNotification() {
if (Notification.permission == 'granted') {
navigator.serviceWorker.getRegistration().then(function(reg) {
var options = {
body: 'Here is a notification body!',
icon: 'images/example.png',
vibrate: [100, 50, 100],
data: {
dateOfArrival: Date.now(),
primaryKey: 1
}
};
reg.showNotification('Hello world!', options);
});
}
}
```
1. 該`body`選項將主要描述添加到通知中。為用戶提供足夠的信息來決定如何對其採取行動。
1. 該`icon`選項附加圖像以使通知更具視覺吸引力,但也與用戶更相關。例如,如果是來自他們朋友的消息,您可能會包含發件人頭像的圖像。
1. 該`vibrate`選項指定接收通知的電話的振動模式。在我們的示例中,手機會振動 100 毫秒,暫停 50 毫秒,然後再次振動 100 毫秒。
1. 該`data`選項將自定義數據附加到通知,以便服務工作者可以在用戶與通知交互時檢索它。例如,向數據添加唯一的`“id”`或`“key”`選項可以讓我們確定當服務工作者處理點擊事件時點擊了哪個通知。
[測試通知選項網站](https://tests.peter.sh/notification-generator/)
#### 向通知添加操作
向用戶發送簡單通知,並在用戶點擊通知時,處理通知的基本互動,可以在通知中添加上下文,就可以讓使用者在不前往網站的情況下與網站互動。
```javascript=
function displayNotification() {
if (Notification.permission == 'granted') {
navigator.serviceWorker.getRegistration().then(function(reg) {
var options = {
body: 'Here is a notification body!',
icon: 'images/example.png',
vibrate: [100, 50, 100],
data: {
dateOfArrival: Date.now(),
primaryKey: 1
},
actions: [
{action: 'explore', title: 'Explore this new world',
icon: 'images/checkmark.png'},
{action: 'close', title: 'Close notification',
icon: 'images/xmark.png'},
]
};
reg.showNotification('Hello world!', options);
});
}
}
```
要使用一組自定義操作的按鈕,我們在通知選項物件中添加一個操作數組。這些物件定義要向用戶顯示的操作按鈕。
動作可以有一個標識符字符串,一個包含要向用戶顯示的文本的標題,以及一個包含要在動作旁邊顯示的圖像的位置的圖標。
### 監聽事件
現在我們需要在 `service worker` 中處理與通知互動(使用`“Interaction API”`)。用戶看到通知後,他們可以將其關閉或對其採取行動。
#### 通知點擊事件
當用戶點擊通知時處理。點擊後會在`service worker`內部觸發一個`notificationclick`事件。
讓我們看一下在 `service worker` 中處理 `click` 事件的代碼。
```javascript=
self.addEventListener('notificationclick', function(e) {
var notification = e.notification;
var primaryKey = notification.data.primaryKey;
var action = e.action;
if (action === 'close') {
notification.close();
} else {
clients.openWindow('http://www.example.com');
notification.close();
}
});
```
可以看到當通知的操作為`close`則關閉通知,否則開啟網頁
### 檢查權限
始終檢查使用通知 API 的權限。請務必檢查是否已授予權限,因為狀態可能會更改:
```javascript=
if (Notification.permission === "granted") {
/* do our magic */
} else if (Notification.permission === "blocked") {
/* the user has previously denied push. Can't reprompt. */
} else {
/* show a prompt to the user */
}
```
## 實作
利用vscode [LiveServe](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer)套件,建立即時更新的本機伺服器,不需再存檔後重整頁面來確認。
### 建立`main.html`
```htmlembedded=
<!DOCTYPE html>
<html lang="en">
<head>
<script>
Notification.requestPermission(function (status) {
console.log("Notification permission status:", status);
registerServiceWorker();
});
function registerServiceWorker() {
if (!("serviceWorker" in navigator)) {
console.log("Service workers aren't supported in this browser.");
return;
}
navigator.serviceWorker
.register("/sw.js") // 註冊 service worker
.then(() => initialiseServiceWorker());
}
function initialiseServiceWorker() {
if (Notification.permission === "granted") {
/* do our magic */
displayNotification();
} else if (Notification.permission === "blocked") {
/* the user has previously denied push. Can't reprompt. */
console.log("用戶之前拒絕推送。 無法重新提示");
var info = document.querySelector(".info");
info.innerHTML = "您之前拒絕推送。 無法重新提示";
} else {
/* show a prompt to the user */
var info = document.querySelector(".info");
info.innerHTML = "請允許通知";
}
}
function displayNotification() {
if (Notification.permission == "granted") {
navigator.serviceWorker.getRegistration().then(function (reg) {
// reg記得在初始化之後,不然會是undefined
var options = {
body: "Here is a notification body!",
icon: "/notification.png",
vibrate: [100, 50, 100],
data: {
dateOfArrival: Date.now(),
primaryKey: 1,
},
actions: [
{
action: "explore",
title: "點擊前往新世界",
icon: "/share.png",
},
{
action: "close",
title: "關閉通知",
icon: "/close.png",
},
],
};
reg.showNotification("Hello world!", options);
});
}
}
</script>
</head>
<body>
<h1>Hello world!</h1>
<p>
<span class="info"></span>
<button onclick="displayNotification()">發送通知</button>
</p>
</body>
</html>
```
### 建立`sw.js`
```javascript=
self.addEventListener("install", (event) => {
console.log("Installed");
});
self.addEventListener("activate", (event) => {
console.log("Activated");
});
self.addEventListener("fetch", (event) => {
console.log("Fetch request");
});
self.addEventListener("notificationclick", function (e) {
var notification = e.notification;
var primaryKey = notification.data.primaryKey;
var action = e.action;
// 如果action是close關閉通知
if (action === "close") {
notification.close();
} else {
// 否的話開啟github,關閉通知
clients.openWindow("https://github.com/");
notification.close();
}
});
```
### 效果如下

[introduction-to-push-notifications](https://developers.google.com/web/ilt/pwa/introduction-to-push-notifications)