如何创建应用徽章

标志用于向用户传达非紧急信息。例如,它们用于表示应用的状态或未读内容的数量。 创建应用标志的经典方法是向网站图标添加数字。在新型浏览器中,用户安装应用后,可以通过内置方式向操作系统任务栏中的应用图标添加标记。

现代方式

使用 navigator.setAppBadge() 方法

navigator.setAppBadge() 方法可在与已安装的应用关联的图标上设置标志。此方法接受可选的单个参数,该参数是一个整数,将用作标志的值。将数字设置为 0 会清除应用标志。如果未提供实参,会生成通用标志,通常显示为彩色的点。

显示实际图标的应用图标,其中数字 3 为标志值。

浏览器支持

  • 81
  • 81
  • x
  • 17

来源

经典方法

向网站图标添加电话号码

如果尚未安装此应用,您可以向网站图标添加一个数字。为此,可以采用多种方法,例如,将网站图标动态绘制到添加了标志信息的画布上,并将其显示为 Blob 网址,或者使用标志信息作为数据网址制作 SVG 图片。

显示以数字 5 作为标记值的实际图标的网站图标。

渐进增强

以下代码段使用自定义元素 <favicon-badge></favicon-badge>,可让开发者通过将整数传递给 badge 属性,在通过 src 属性指定的网站图标上以声明方式设置标记。当用户安装应用时,该标志会“升级”为原生操作系统标志。

import 'https://unpkg.com/favicon-badge@2.0.0/dist/FavIconBadge.js';

// DOM references.
const favicon = document.querySelector('favicon-badge');
const installButton = document.querySelector('button');

// Feature detection.
const supportsAppBadge = 'setAppBadge' in navigator;

let setAppBadge;

// For the demo simply set the badge between [0, 9].
let i = 0;
const getAppBadgeValue = () => {
  if (i > 9) {
    i = 0;
  }
  return i++;
};

// Set the badge on the favicon.
const setAppBadgeFavicon = (value) => {
  favicon.badge = value;
};

// Set the native operating system badge.
const setAppBadgeNative = (value) => {
  navigator.setAppBadge(value);
}

// If the app is installed and the Badging API is supported,
// set the badge on the native operating system. Else, fall
// back to the favicon.
if (
  matchMedia('(display-mode: standalone)').matches &&
  supportsAppBadge
) {
  setAppBadge = setAppBadgeNative;
} else {
  setAppBadge = setAppBadgeFavicon;
}

// Set a new badge every second.
setInterval(() => {
  setAppBadge(getAppBadgeValue());
}, 1000);

// If installation is supported…
if ('BeforeInstallPromptEvent' in window) {
  let installEvent = null;
  const onInstall = () => {
    // After installation, "upgrade" to the native operating system badge.
    installButton.disabled = true;
    installEvent = null;
    if (supportsAppBadge) {
      favicon.badge = false;
      setAppBadge = setAppBadgeNative;
    }
  };

  // …listen for the `beforeinstallprompt` event.
  window.addEventListener('beforeinstallprompt', (event) => {
    event.preventDefault();
    installEvent = event;
    installButton.disabled = false;
  });

  // Deal with installation.
  installButton.addEventListener('click', async () => {
    if (!installEvent) {
      return;
    }
    installEvent.prompt();
    const result = await installEvent.userChoice;
    if (result.outcome === 'accepted') {
      onInstall();
    }
  });

  // Listen for the `appinstalled` in case the user installs the app manually.
  window.addEventListener('appinstalled', (event) => {
    onInstall();
  });
}

深入阅读

演示

HTML

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link rel="manifest" href="manifest.json" />
    <title>How to create an app badge</title>
    <link rel="stylesheet" href="style.css" />
    <!-- TODO: Devsite - Removed inline handlers -->
    <!-- <script>
      if ('serviceWorker' in navigator) {
        window.addEventListener('load', async () => {
          const registration = await navigator.serviceWorker.register(
            'sw.js',
          );
          console.log(
            'Service worker registered for scope',
            registration.scope,
          );
        });
      }
    </script>
    <script src="script.js" type="module"></script> -->
  </head>
  <body>
    <h1>How to create an app badge</h1>
    <ol>
      <li>
        Watch the favicon. You should see a counter that updates each second
        integrated into the favicon.
        <img
          src="../favicon.png"
          style="width: 250px; height: auto"
          width="528"
          height="74"
          alt="Favicon with counter."
        />
      </li>
      <li>
        Install the app by clicking the button below. After the installation,
        the button is disabled.
        <p>
          <button disabled type="button">Install</button>
        </p>
      </li>
      <li>
        Watch the app icon in your operating system's task bar. You should see a
        counter that updates each second as an app badge.
        <img
          src="../app-badge.png"
          style="width: 80px; height: auto"
          width="282"
          height="388"
          alt="App badge with counter."
        />
      </li>
    </ol>
    <favicon-badge src="../favicon.svg" textColor="#fff" badge="" />
  </body>
</html>

CSS


        html {
  box-sizing: border-box;
  font-family: system-ui, sans-serif;
  color-scheme: dark light;
}

*, *:before, *:after {
  box-sizing: inherit;
}

body {
  margin: 1rem;
}

img {
  height: auto;
  max-width: 100%;
  display: block;
}
        

JS


        import 'https://unpkg.com/favicon-badge@2.0.0/dist/FavIconBadge.js';

// The `` custom element.
const favicon = document.querySelector('favicon-badge');
// The install button.
const installButton = document.querySelector('button');

// Feature detection.
const supportsAppBadge = 'setAppBadge' in navigator;

// This function will either set the favicon or the native
// app badge. The implementation is dynamically changed at runtime.
let setAppBadge;

// Variable for the counter.
let i = 0;

// Returns a value between 0 and 9.
const getAppBadgeValue = () => {
  if (i > 9) {
    i = 0;
  }
  return i++;
};

// Function to set a favicon badge.
const setAppBadgeFavicon = (value) => {
  favicon.badge = value;
};

// Function to set a native app badge.
const setAppBadgeNative = (value) => {
  navigator.setAppBadge(value);
}

// If the app is installed and native app badges are supported,
// use the native app badge.
if (
  matchMedia('(display-mode: standalone)').matches &&
  supportsAppBadge
) {
  setAppBadge = setAppBadgeNative;
// In all other cases (i.e., if the app is not installed or native
//  app badges are not supported), use the favicon badge.
} else {
  setAppBadge = setAppBadgeFavicon;
}

// Update the badge every second.
setInterval(() => {
  setAppBadge(getAppBadgeValue());
}, 1000);

// Only relevant for browsers that support installation.
if ('BeforeInstallPromptEvent' in window) {
  // Variable to stash the `BeforeInstallPromptEvent`.
  let installEvent = null;

  // Function that will be run when the app is installed.
  const onInstall = () => {
    // Disable the install button.
    installButton.disabled = true;
    // No longer needed.
    installEvent = null;

    if (supportsAppBadge) {
      // Remove the favicon badge.
      favicon.badge = false;
      // Switch the implementation so it uses the native
      // app badge.
      setAppBadge = setAppBadgeNative;
    }
  };

  window.addEventListener('beforeinstallprompt', (event) => {
    // Do not show the install prompt quite yet.
    event.preventDefault();
    // Stash the `BeforeInstallPromptEvent` for later.
    installEvent = event;
    // Enable the install button.
    installButton.disabled = false;
  });

  installButton.addEventListener('click', async () => {
    // If there is no stashed `BeforeInstallPromptEvent`, return.
    if (!installEvent) {
      return;
    }
    // Use the stashed `BeforeInstallPromptEvent` to prompt the user.
    installEvent.prompt();
    const result = await installEvent.userChoice;
    // If the user installs the app, run `onInstall()`.
    if (result.outcome === 'accepted') {
      onInstall();
    }
  });

  // The user can decide to ignore the install button
  // and just use the browser prompt directly. In this case
  // likewise run `onInstall()`.
  window.addEventListener('appinstalled', (event) => {
    onInstall();
  });
}