使用 Web Notifications
====================

**實驗性質:** **這是一個實驗中的功能 (en-US)**  
此功能在某些瀏覽器尚在開發中，請參考兼容表格以得到不同瀏覽器用的前輟。

摘要
--

Web Notifications API 可將通知傳送至頁面以外的系統層級並顯示通知。因此即使 Web Apps 處於閒置狀態，亦可傳送資訊予使用者。絕佳範例之一，就是在使用其他 Apps 時，Web Mail App 同樣可通知使用者已接收到新郵件。

要求權限
----

### 網頁內容

在 Apps 傳送通知之前，使用者必須先許可 Apps 的動作。只要 APIs 嘗試予網頁之外的東西互動，均必須先獲得使用者的授權。如此可避免濫發通知而影響使用經驗。

透過 `Notification.permission` (en-US) 唯讀屬性，要傳送通知的 Apps 將檢查目前的授權狀態。此屬性共有 3 組參數：

* `default`：使用者尚未給予任何權限 (因此不會顯示任何通知)
* `granted`：使用者允許接收到 Apps 的通知
* `denied`：使用者拒絕接收 Apps 的通知

**備註：** Chrome 與 Safari 尚未建構 `permission` 屬性。

若使用者尚未給予權限，則 Apps 必須透過 `Notification.requestPermission()` (en-US) 函式讓使用者選擇，接著由此函式接收 1 組回呼 (Callback) 函式作為參數；而該回呼函式則提供使用者是否授權的資訊。

以下為啟動 Apps 時要求權限的常用範例：


```js
window.addEventListener("load", function () {
  Notification.requestPermission(function (status) {
    // This allows to use Notification.permission with Chrome/Safari
    if (Notification.permission !== status) {
      Notification.permission = status;
    }
  });
});
```


**備註：** Chrome 不允許於載入事件中呼叫 `Notification.requestPermission()` (en-US) (參閱 issue 274284)。

### 已安裝的 Apps

在安裝 Apps 之後，若於 Apps 的 manifest 檔案中直接添加權限，即可省去再次向使用者要求權限的動作。


```json
permissions: {
  "desktop-notification": {
    "description: "Allows to display notifications on the user's desktop.
  }
}
```

建立通知
----

透過 `Notification` 建構子 (Constructor) 即可建立通知。此建構子包含 1 組標題，可於通知內顯示；另有如 `icon` (en-US) 或文字 `body` (en-US) 等數個選項，可強化通知的內容。

在建立實體 (Instantiated) 之後，就會儘快顯示通知。若要追蹤通知的目前狀態，必須在 `Notification` 的實體階層觸發 4 個事件：

* show：對使用者顯示通知之後，隨即觸發
* click (en-US)：使用者點擊通知之後，隨即觸發
* close：關閉通知之後，隨即觸發
* error (en-US)：通知發生任何錯誤 (大多數是因為某種情況而未顯示通知)，隨即觸發

而透過 `onshow` (en-US)、`onclick` (en-US)、`onclose` (en-US)，或 `onerror` (en-US) 等事件處理器 (Event handler)，即可追蹤這些事件。由於 `Notification` 是繼承 `EventTarget` 而來，因此亦可使用 `addEventListener()` (en-US) 函式。

**備註：** Firefox 與 Safari 並未遵守 close 事件的規格。此規格雖然規定「僅限使用者能關閉通知」，但 Firefox 與 Safari 卻可於數分鐘後自動關閉通知。因此不一定是由使用者關閉通知。此規格並明確規定「應透過 `Notification.close()` (en-US) 函式，於應用程式層級完成自動關閉通知」。範例程式碼如下：


```js
var n = new Notification("Hi!");
n.onshow = function () {
  setTimeout(n.close, 5000);
};
```


### 簡易範例

先假設下列基本 HTML：


```html
<button>Notify me!</button>
```


則能以這種方法處理通知：


```js
window.addEventListener("load", function () {
  // At first, let's check if we have permission for notification
  // If not, let's ask for it
  if (Notification && Notification.permission !== "granted") {
    Notification.requestPermission(function (status) {
      if (Notification.permission !== status) {
        Notification.permission = status;
      }
    });
  }
  var button = document.getElementsByTagName("button")[0];
  button.addEventListener("click", function () {
    // If the user agreed to get notified
    if (Notification && Notification.permission === "granted") {
      var n = new Notification("Hi!");
    }
    // If the user hasn't told if he wants to be notified or not
    // Note: because of Chrome, we are not sure the permission property
    // is set, therefore it's unsafe to check for the "default" value.
    else if (Notification && Notification.permission !== "denied") {
      Notification.requestPermission(function (status) {
        if (Notification.permission !== status) {
          Notification.permission = status;
        }
        // If the user said okay
        if (status === "granted") {
          var n = new Notification("Hi!");
        }
        // Otherwise, we can fallback to a regular modal alert
        else {
          alert("Hi!");
        }
      });
    }
    // If the user refuses to get notified
    else {
      // We can fallback to a regular modal alert
      alert("Hi!");
    }
  });
});
```

### 現場測試結果

若無法顯示，可至本文右上角「Language」切換回英文原文觀看。

處理多筆通知
------

某些情況下 (如某個即時訊息 App 持續通知每一筆進來的訊息)，使用者可能會接收大量的通知。為了避免太多非必要訊息擠爆使用者的桌面，則應該讓等待中的通知進入佇列。

將標籤添加至任何新的通知，即可達到佇列效果。若通知擁有相同的標籤且尚未顯示，則新通知就會取代先前的通知；反之，若已顯示了相同標籤的通知，就會關閉先前的通知而顯示新通知。

### 標籤範例

先假設下列基本 HTML：


```html
<button>Notify me!</button>
```


則能以下列方式處理多筆通知：


```js
window.addEventListener('load', function () {
  // At first, let's check if we have permission for notification
  // If not, let's ask for it
  if (Notification && Notification.permission !== "granted") {
    Notification.requestPermission(function (status) {
      if (Notification.permission !== status) {
        Notification.permission = status;
      }
    });
  }
  var button = document.getElementsByTagName('button')[0];
  button.addEventListener('click', function () {
    // If the user agreed to get notified
    // Let's try to send ten notifications
    if (Notification && Notification.permission === "granted") {
      for (var i = 0; i < 10; i++) {
        // Thanks to the tag, we should only see the "Hi! 10" notification
        var n = new Notification("Hi! " + i, {tag: 'soManyNotification'});
      }
    }
    // If the user hasn't told if he wants to be notified or not
    // Note: because of Chrome, we are not sure the permission property
    // is set, therefore it's unsafe to check for the "default" value.
    else if (Notification && Notification.permission !== "denied") {
      Notification.requestPermission(function (status) {
        if (Notification.permission !== status) {
          Notification.permission = status;
        }
        // If the user said okay
        if (status === "granted") {
          for (var i = 0; i < 10; i++) {
            // Thanks to the tag, we should only see the "Hi! 10" notification
            var n = new Notification("Hi! " + i, {tag: 'soManyNotification'});
          }
        }
        // Otherwise, we can fallback to a regular modal alert
        else {
          alert(Hi!");
        }
      });
    }
    // If the user refuses to get notified
    else {
      // We can fallback to a regular modal alert
      alert(Hi!");
    }
  });
});
```


#### 現場測試結果

若無法顯示，可至本文右上角「Language」切換回英文原文觀看。

規格
--

| Specification |
| --- |
| Notifications API Standard # api |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

另可參閱
----

* `Notification`