--- 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(); } }); ``` ### 效果如下 ![](https://i.imgur.com/O8T13jJ.gif) [introduction-to-push-notifications](https://developers.google.com/web/ilt/pwa/introduction-to-push-notifications)