1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
|
---
title: 使用 Web Notifications
slug: Web/API/Notifications_API/Using_the_Notifications_API
tags:
- Firefox OS
- Notifications
- Using the Notifications API
- 通知
translation_of: Web/API/Notifications_API/Using_the_Notifications_API
original_slug: Web/API/notification/Using_Web_Notifications
---
<p>{{APIRef("Web Notifications")}}</p>
<p class="summary"><a href="https://developer.mozilla.org/en-US/docs/Web/API/Notifications_API">Notifications API</a> 允许网页或应用程序在系统级别发送在页面外部显示的通知;这样即使应用程序空闲或在后台,Web应用程序也会向用户发送信息。本文将介绍在您自己的应用程序中使用此API的基础知识。</p>
<p>{{AvailableInWorkers}}</p>
<p>通常,系统通知是指操作系统的标准通知机制,例如思考典型的桌面系统或移动设备如何发布通知。</p>
<p><img src="https://mdn.mozillademos.org/files/10959/android-notification.png"></p>
<p><img src="https://mdn.mozillademos.org/files/10961/mac-notification.png"></p>
<p>系统通知系统当然会因平台和浏览器而异,但无需担心,通知API被编写为通用的,足以与大多数系统通知系统兼容。</p>
<p>Web Notifications API 使页面可以发出通知,通知将被显示在页面之外的系统层面上(通常使用操作系统的标准通知机制,但是在不同的平台和浏览器上的表现会有差异)。这个功能使 web 应用可以向用户发送信息,即使应用处于空闲状态。最明显的用例之一是一个网页版电子邮件应用程序,每当用户收到了一封新的电子邮件都需要通知用户,即使用户正在使用另一个应用程序。</p>
<p>要显示一条通知,你需要先请求适当的权限,然后你可以实例化一个 {{domxref("Notification")}} 实例:</p>
<pre class="brush: js">Notification.requestPermission( function(status) {
console.log(status); // 仅当值为 "granted" 时显示通知
var n = new Notification("title", {body: "notification body"}); // 显示通知
});
</pre>
<h2 id="请求权限">请求权限</h2>
<p>在应用可以发送通知之前,用户必须授予应用有权这么做。这是一个常见的要求,当一个 API 至少一次试图与 web 页外部进行交互时,用户不得不专门授予该应用程序有权限提出通知,从而让用户控制允许哪些应用程序或网站显示通知。</p>
<h3 id="检查当前权限状态">检查当前权限状态</h3>
<p>你可以通过检查只读属性 {{domxref("Notification.permission")}} 的值来查看你是否已经有权限。该属性的值将会是下列三个之一:</p>
<dl>
<dt><code>default</code></dt>
<dd>用户还未被询问是否授权,所以通知不会被显示。参看 <a href="#获得权限">获得权限</a> 以了解如何请求显示通知的权限。</dd>
<dt><code>granted</code></dt>
<dd>表示之前已经询问过用户,并且用户已经授予了显示通知的权限。</dd>
<dt><code>denied</code></dt>
<dd>用户已经明确的拒绝了显示通知的权限。</dd>
</dl>
<div class="note">
<p><strong>注:</strong>Safari 和 <span style="line-height: 1.5;">Chrome (在 32 版本之前)</span><span style="line-height: 1.5;"> 还没有实现 </span><code style="font-style: italic; line-height: 1.5;">permission</code><span style="line-height: 1.5;"> 属性。</span></p>
</div>
<h3 id="获得权限">获得权限</h3>
<p>如果权限尚未被授予,那么应用不得不通过 {{domxref("Notification.requestPermission()")}} 方法让用户进行选择。这个方法接受一个回调函数,一旦用户回应了显示通知的请求,将会调用这个函数。</p>
<p>通常你应在你的应用首次初始化的时候请求显示通知的权限:</p>
<pre class="brush: js">window.addEventListener('load', function () {
Notification.requestPermission(function (status) {
// 这将使我们能在 Chrome/Safari 中使用 Notification.permission
if (Notification.permission !== status) {
Notification.permission = status;
}
});
});</pre>
<div class="note">
<p><strong>注:</strong>Chrome 不允许你在 <code>load</code> 事件处理中调用 {{domxref("Notification.requestPermission()")}} (参见 <a href="https://code.google.com/p/chromium/issues/detail?id=274284" title="https://code.google.com/p/chromium/issues/detail?id=274284">issue 274284</a>)。</p>
</div>
<h3 id="Notification_API_的清单权限">Notification API 的清单权限</h3>
<p>请注意 Notification API 不是 {{Glossary("privileged")}} 或 {{Glossary("certified")}},因此当你在一个开放 web 应用中使用它时,你仍需要在你的 <code>manifest.webapp</code> 文件中包含以下项目:</p>
<pre>"permissions": {
"desktop-notification": {
"description": "Needed for creating system notifications."
}
}</pre>
<div class="note">
<p><strong>注:</strong>当安装应用程序时,你不需要通过上面的代码显式的请求权限,但您仍然需要在触发通知之前取得权限项。</p>
</div>
<h2 id="创建通知">创建通知</h2>
<p>创建通知很简单,只需要用 {{domxref("Notification")}} 构造方法。这个构造函数需要一个用来显示在通知内的标题以及一些用来增强通知的选项,例如 {{domxref("Notification.icon","icon")}} 或文本 {{domxref("Notification.body","body")}}。</p>
<p>一旦通知被创建出来,它会立即被显示出来。为了跟踪通知当前的状态,在 {{domxref("Notification")}} 实例层面上会有4个事件被触发:</p>
<dl>
<dt>{{event("show")}}</dt>
<dd>当通知被显示给用户时触发。</dd>
<dt>{{event("click")}}</dt>
<dd>当用户点击通知时触发。</dd>
<dt>{{event("close")}}</dt>
<dd>当通知被关闭时触发。</dd>
<dt>{{event("error")}}</dt>
<dd>当通知发生错误的时候触发。这通常是因为通知由于某些原因而无法显示。</dd>
</dl>
<p>这些事件可以通过事件处理跟踪 {{domxref("Notification.onshow","onshow")}}、{{domxref("Notification.onclick","onclick")}}、{{domxref("Notification.onclose","onclose")}} 和 {{domxref("Notification.onerror","onerror")}}。因为 {{domxref("Notification")}} 同样继承自 {{domxref("EventTarget")}},因此可以对它调用 {{domxref("EventTarget.addEventListener","addEventListener()")}} 方法。</p>
<div class="note">
<p><strong>注:</strong>Firefox 和 Safari 会在一定时间后自动关闭通知(大约4秒)。这也会发生在操作系统层面。</p>
<p>当然你也可以通过代码做到,调用 {{domxref("Notification.close()")}} 方法,就像下面的代码一样:</p>
<pre class="brush: js">var n = new Notification("Hi!");
n.onshow = function () {
setTimeout(n.close.bind(n), 5000);
}
</pre>
<p>当你接收到一个“close”事件时,并不能保证这个通知是被用户关闭的。这是符合规范的,其中指出:“当一个通知被关闭时,通知的关闭动作都必须执行,不论是底层通知平台导致,还是用户导致。”</p>
</div>
<h3 id="Simple_example">简单的例子</h3>
<p>假定有如下的 HTML:</p>
<pre class="brush: html"><button>Notify me!</button></pre>
<p>它可能通过这样的方式处理通知:</p>
<pre class="brush: js">window.addEventListener('load', function () {
// 首先,让我们检查我们是否有权限发出通知
// 如果没有,我们就请求获得权限
if (window.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 (window.Notification && Notification.permission === "granted") {
var n = new Notification("Hi!");
}
// 如果用户没有选择是否显示通知
// 注:因为在 Chrome 中我们无法确定 permission 属性是否有值,因此
// 检查该属性的值是否是 "default" 是不安全的。
else if (window.Notification && Notification.permission !== "denied") {
Notification.requestPermission(function (status) {
if (Notification.permission !== status) {
Notification.permission = status;
}
// 如果用户同意了
if (status === "granted") {
var n = new Notification("Hi!");
}
// 否则,我们可以让步的使用常规模态的 alert
else {
alert("Hi!");
}
});
}
// 如果用户拒绝接受通知
else {
// 我们可以让步的使用常规模态的 alert
alert("Hi!");
}
});
});</pre>
<p>这是实际的结果:</p>
<p>{{ EmbedLiveSample('Simple_example', '100%', 30) }}</p>
<h2 id="处理重复的通知">处理重复的通知</h2>
<p>某些情况下对于用户来说,显示大量通知是件令人痛苦的事情。比如,如果一个即时通信应用向用户提示每一条传入的消息。为了避免数以百计的不必要通知铺满用户的桌面,可能需要接管一个挂起消息的队列。</p>
<p>因此,需要为新建的通知添加一个标记。如果有一条通知也具有一个相同的标记,并且还没有被显示,那么这条新通知将会替换上一条通知。如果有一条通知具有一个相同的标记,并且已经显示出来了,那么上一条通知将会被关闭,新通知将会被显示出来。</p>
<h3 id="Tag_example">使用标记的例子</h3>
<p>假定有如下 HTML:</p>
<pre class="brush: html"><button>Notify me!</button></pre>
<p>它有可能通过这种方式处理的多个通知:</p>
<pre class="brush: js">window.addEventListener('load', function () {
// 首先,我们检查是否具有权限显示通知
// 如果没有,我们就申请权限
if (window.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 () {
// 如果用户同意接收通知,我们就尝试发送10条通知
if (window.Notification && Notification.permission === "granted") {
for (var i = 0; i < 10; i++) {
// 感谢标记,我们应该只看到内容为 "Hi! 9" 的通知
var n = new Notification("Hi! " + i, {tag: 'soManyNotification'});
}
}
// 如果用户没有选择是否同意显示通知
// 注:由于在 Chrome 中不能确定 permission 属性是否有值,因此检查
// 该属性值是否为 "default" 是不安全的。
else if (window.Notification && Notification.permission !== "denied") {
Notification.requestPermission(function (status) {
if (Notification.permission !== status) {
Notification.permission = status;
}
// 如果用户同意
if (status === "granted") {
for (var i = 0; i < 10; i++) {
// Thanks to the tag, we should only see the "Hi! 9" notification
var n = new Notification("Hi! " + i, {tag: 'soManyNotification'});
}
}
// 否则改用 alert
else {
alert("Hi!");
}
});
}
// 如果用户拒绝
else {
// 改用 alert
alert("Hi!");
}
});
});</pre>
<p>实际效果如下:</p>
<p>{{ EmbedLiveSample('Tag_example', '100%', 30) }}</p>
<h2 id="接收点击应用通知的通知">接收点击应用通知的通知</h2>
<p>当用户点击一个由应用产生的通知时,视情况而定,你将会有两种方式被告知点击事件发生了:</p>
<ol>
<li>如果你的程序没有被关闭或转入后台,那么在你会收到一个点击事件。</li>
<li>其他情况下会收到一条系统消息。</li>
</ol>
<p>参考 <a href="https://github.com/mozilla/buddyup/commit/829cba7afa576052cf601c3e286b8d1981f93f45#diff-3">这个代码片段</a> 作为例子,展示了如何处理。</p>
<h2 id="规范">规范</h2>
<table class="standard-table">
<thead>
<tr>
<th scope="col">规范</th>
<th scope="col">状态</th>
<th scope="col">备注</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{SpecName('Web Notifications')}}</td>
<td>{{Spec2('Web Notifications')}}</td>
<td>Initial specification.</td>
</tr>
</tbody>
</table>
<h2 id="浏览器兼容性">浏览器兼容性</h2>
{{Compat("api.Notification")}}
<h2 id="参考">参考</h2>
<ul>
<li>{{ domxref("Notification") }}</li>
</ul>
|