Web的通知:`Notification API`的使用与权限。

Web的通知:Notification API的使用与权限

大家好,今天我们来深入探讨Web的通知功能,也就是Notification API。我们将从权限管理入手,逐步讲解API的使用方法,并结合实际案例,帮助大家掌握这一强大的Web特性。

1. 通知权限:请求与状态

在浏览器中显示通知之前,我们必须先获得用户的许可。这是出于安全和用户体验的考虑,避免未经授权的垃圾通知干扰用户。Notification API提供了requestPermission()方法来请求权限,以及permission属性来查询当前权限状态。

1.1 请求权限:requestPermission()

Notification.requestPermission()方法会弹出一个对话框,询问用户是否允许当前网站显示通知。这个方法返回一个Promise,resolve的值是用户授权的结果。

Notification.requestPermission().then(permission => {
  console.log("Permission granted:", permission); // "granted", "denied", or "default"
  if (permission === "granted") {
    // 用户允许通知
    console.log("Notification permission granted.");
  } else if (permission === "denied") {
    // 用户拒绝通知
    console.log("Notification permission denied.");
  } else {
    // 用户未做选择(点击了取消或者关闭了对话框)
    console.log("Notification permission dismissed.");
  }
});

需要注意的是,requestPermission()方法只能由用户交互(比如点击按钮)触发,不能在页面加载时自动调用。否则,浏览器会阻止该请求,并可能将网站标记为滥用通知的站点。

1.2 查询权限状态:permission

Notification.permission属性返回一个字符串,表示当前的通知权限状态。它有三个可能的值:

  • granted: 用户已明确允许显示通知。
  • denied: 用户已明确拒绝显示通知。
  • default: 用户尚未做出选择。
if (Notification.permission === "granted") {
  // 已经授权,可以显示通知
  console.log("Already have permission to show notifications.");
  // showNotification(); // 稍后会讲解这个函数
} else if (Notification.permission === "denied") {
  // 用户拒绝了通知
  console.log("Permission to show notifications was denied.");
} else {
  // 尚未授权,需要请求权限
  console.log("Requesting notification permission...");
  Notification.requestPermission().then(permission => {
    if (permission === "granted") {
      console.log("Notification permission granted.");
      // showNotification(); // 稍后会讲解这个函数
    }
  });
}

1.3 最佳实践:优雅地处理权限

  • 仅在必要时请求权限: 不要一开始就请求权限,而是在用户需要接收通知的时候再请求,比如用户订阅了某种更新。
  • 解释请求原因: 在请求权限之前,向用户解释为什么需要通知权限,以及通知将如何帮助他们。
  • 提供取消订阅选项: 让用户可以随时取消订阅通知,并尊重用户的选择。
  • 避免打扰用户: 不要发送过多的通知,确保通知内容是有价值的。

2. 创建和显示通知

一旦获得了用户的许可,我们就可以创建和显示通知了。Notification API提供了一个Notification构造函数,用于创建通知对象。

2.1 Notification构造函数

Notification构造函数接受两个参数:

  • title (必需): 通知的标题。
  • options (可选): 一个对象,包含通知的配置选项。
const notification = new Notification("Hello World!", {
  body: "This is a simple notification.",
  icon: "/images/icon.png", // 通知图标
  badge: "/images/badge.png", // 用于在状态栏中显示的徽章图标(仅限Android)
  data: { id: 123 }, // 自定义数据
  tag: "my-notification", // 用于替换旧通知的标签
  renotify: true, //  设置为 true 时,即使具有相同 tag 的通知已经显示,也会重新通知用户
  silent: false, // 设置为 true 时,通知不会发出声音或振动
  vibrate: [200, 100, 200], // 振动模式(仅限Android)
  actions: [ // 通知上的操作按钮
    { action: "view", title: "View" },
    { action: "dismiss", title: "Dismiss" }
  ]
});

2.2 options 参数详解

选项 类型 描述
body string 通知的正文内容。
icon string 通知的图标 URL。
image string 在通知中显示的图像 URL。
badge string 用于在状态栏中显示的徽章图标 URL(仅限Android)。
data any 与通知关联的自定义数据。
tag string 用于替换旧通知的标签。如果两个通知具有相同的标签,则新通知将替换旧通知。
renotify boolean 设置为 true 时,即使具有相同 tag 的通知已经显示,也会重新通知用户。
silent boolean 设置为 true 时,通知不会发出声音或振动。
vibrate number[] 振动模式(仅限Android)。是一个数字数组,表示振动和暂停的毫秒数。例如,[200, 100, 200] 表示振动 200 毫秒,暂停 100 毫秒,再振动 200 毫秒。
actions object[] 通知上的操作按钮。每个操作对象包含 actiontitle 属性。
dir string 文字方向,可以是 ltr(从左到右)、rtl(从右到左)或 auto
lang string 通知的语言代码。

2.3 显示通知

创建通知对象后,它会自动显示在用户的屏幕上。

// 假设已经获得了通知权限
const showNotification = () => {
  const notification = new Notification("Example Notification", {
    body: "This is an example notification!",
    icon: "/images/icon.png"
  });
};

if (Notification.permission === "granted") {
  showNotification();
} else if (Notification.permission !== "denied") {
  Notification.requestPermission().then(permission => {
    if (permission === "granted") {
      showNotification();
    }
  });
}

3. 处理通知事件

Notification对象会触发一系列事件,我们可以监听这些事件来执行相应的操作。

3.1 show 事件

当通知显示时,会触发show事件。

const notification = new Notification("Show Event", {
  body: "This notification demonstrates the show event."
});

notification.onshow = () => {
  console.log("Notification is shown.");
  // 例如,可以记录通知的显示时间
};

3.2 close 事件

当通知关闭时,会触发close事件。关闭的原因可以是用户手动关闭,或者通知超时自动关闭。

const notification = new Notification("Close Event", {
  body: "This notification demonstrates the close event."
});

notification.onclose = (event) => {
  console.log("Notification is closed.", event.reason);
  // event.reason 属性表示关闭的原因,可以是 "user"(用户关闭)或 "timeout"(超时关闭)
};

3.3 click 事件

当用户点击通知时,会触发click事件。

const notification = new Notification("Click Event", {
  body: "Click this notification to see the event.",
  data: { url: "https://www.example.com" }
});

notification.onclick = (event) => {
  console.log("Notification is clicked.", event);
  // 例如,可以打开一个网页
  window.open(event.target.data.url, "_blank");
  notification.close(); // 关闭通知
};

3.4 error 事件

当创建或显示通知时发生错误,会触发error事件。

const notification = new Notification("Error Event", {
  body: "This notification might trigger an error."
});

notification.onerror = (event) => {
  console.error("Notification error:", event.error);
  // 例如,可以记录错误信息,并向用户显示一个友好的提示
};

3.5 事件监听总结

事件 描述
show 通知显示时触发。
close 通知关闭时触发。
click 用户点击通知时触发。
error 创建或显示通知时发生错误时触发。

4. 使用tag属性管理通知

tag属性允许我们替换旧的通知。如果两个通知具有相同的tag,则新的通知将替换旧的通知,而不是显示两个独立的通知。这对于更新通知内容非常有用,例如,实时更新消息计数。

let notification;

function showNotification(message) {
  if (notification) {
    notification.close(); // 关闭旧的通知
  }

  notification = new Notification("New Message", {
    body: message,
    tag: "new-message"
  });

  notification.onclick = () => {
    console.log("View message");
    notification.close();
  };
}

// 模拟收到新消息
setTimeout(() => {
  showNotification("You have a new message!");
}, 1000);

setTimeout(() => {
  showNotification("You have two new messages!"); // 这将替换之前的通知
}, 3000);

在这个例子中,第一个通知会在1秒后显示,然后第二个通知会在3秒后显示,并替换第一个通知。用户只会看到最新的消息计数。

5. 使用Service Worker发送推送通知

虽然Notification API可以在网页中直接使用,但是它依赖于网页的活动状态。如果用户关闭了网页,或者浏览器关闭了网页的标签页,那么通知就无法显示了。为了解决这个问题,我们可以使用Service Worker来发送推送通知。

Service Worker是一个在后台运行的脚本,它可以拦截网络请求、缓存资源、以及发送推送通知。即使网页关闭了,Service Worker仍然可以运行,并接收来自服务器的推送消息,然后显示通知。

5.1 注册Service Worker

首先,我们需要注册一个Service Worker。

if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/service-worker.js')
    .then(registration => {
      console.log('Service Worker registered with scope:', registration.scope);
    })
    .catch(error => {
      console.error('Service Worker registration failed:', error);
    });
}

5.2 在Service Worker中处理推送消息

在Service Worker中,我们需要监听push事件,当收到推送消息时,显示通知。

// service-worker.js
self.addEventListener('push', event => {
  const data = event.data.json();
  const title = data.title;
  const options = {
    body: data.body,
    icon: data.icon
  };

  event.waitUntil(self.registration.showNotification(title, options));
});

self.addEventListener('notificationclick', function(event) {
  event.notification.close();

  // 执行某些操作,例如打开一个网页
  event.waitUntil(
    clients.openWindow('https://www.example.com')
  );
});

5.3 从服务器发送推送消息

要从服务器发送推送消息,我们需要使用Web Push协议。Web Push协议使用加密的方式,确保消息的安全性和隐私性。

  • 生成VAPID密钥: 首先,我们需要生成一对VAPID密钥(Voluntary Application Server Identification)。VAPID密钥用于标识我们的服务器,并防止恶意服务器发送推送消息。可以使用一些在线工具或者Node.js库来生成VAPID密钥。

  • 订阅推送: 在客户端,我们需要订阅推送服务,并获取一个推送订阅对象。推送订阅对象包含一个endpoint和一个keys对象,用于标识用户的设备。

  • 发送推送消息: 将推送订阅对象发送到服务器,然后服务器可以使用Web Push库(例如web-push)来发送推送消息。

// 服务器端 (Node.js)
const webpush = require('web-push');

// 设置VAPID密钥
webpush.setVapidDetails(
  'mailto:[email protected]',
  'PUBLIC_VAPID_KEY',
  'PRIVATE_VAPID_KEY'
);

// 推送订阅对象(从客户端获取)
const subscription = {
  endpoint: '...',
  keys: {
    p256dh: '...',
    auth: '...'
  }
};

const payload = JSON.stringify({
  title: 'New Push Notification',
  body: 'This is a push notification from the server!',
  icon: '/images/icon.png'
});

// 发送推送消息
webpush.sendNotification(subscription, payload)
  .then(result => console.log('Push notification sent:', result))
  .catch(error => console.error('Push notification error:', error));

5.4 Service Worker实现推送的优势

优势 描述
离线推送 即使网页关闭,Service Worker仍然可以接收推送消息并显示通知。
可靠性 Service Worker在后台运行,可以确保推送消息的可靠传递。
节省资源 Service Worker可以缓存资源,减少网络请求,提高网页性能。

6. 注意事项与最佳实践

  • 用户体验至上: 尊重用户的选择,不要滥用通知。
  • 错误处理: 妥善处理通知相关的错误,避免影响用户体验。
  • 跨浏览器兼容性: 测试你的代码在不同浏览器上的兼容性。
  • 安全性: 确保你的通知内容是安全的,避免包含恶意链接或代码。
  • 无障碍性: 确保你的通知内容是可访问的,例如提供文字描述或替代方案。
  • 使用HTTPS: Service Worker 必须在 HTTPS 环境下运行。
  • 测试: 在各种设备和浏览器上测试您的通知实现。

一些值得关注的点

权限管理至关重要,合理的使用通知能提升用户体验,不恰当的使用则会适得其反。利用Service Worker 可以实现离线推送,极大提升Web应用的推送能力。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注