如何创建自动更改的 Favicon

Avatar of Carlo Martinucci
Carlo Martinucci

DigitalOcean 为您的旅程每个阶段提供云产品。 立即开始使用 价值 200 美元的免费积分!

前几天我发现了这个 免费 Favicon 制造器。 这是一个制作 Favicon(顾名思义)的好工具,但与其他 Favicon 生成器不同,它允许您从字符或表情符号开始从头开始创建 Favicon。 自然地,我很好奇地查看代码以了解它的工作原理,并且在我这样做的时候,它让我想到了不同的方向。 我被提醒了读过的一句话,它说可以动态地更改网站的 Favicon。 实际上,一些网站将其用作一种用户通知:将 Favicon 更改为红点或其他指示器,以传达页面上正在发生或已更改的事情。

我开始通过 emojipedia.org 浏览表情符号以寻找灵感,就在那时,它击中了:为什么不使用时钟表情符号 (🕛) 和其他相关的 Favicon 来显示时间? 这个想法是每分钟检查一次时间,并将 Favicon 设置为指示当前时间的相应时钟表情符号。

我们将在本文中完全做到这一点,并且它将使用纯 JavaScript 工作。 尽管我经常将 Gatsby 用于静态网站,但我们还将展示如何在 React 中执行此操作。 从那里开始,无论您想如何以及如何使用 Favicon,这些想法都应该是可用的。

这是一个将表情符号作为参数并返回一个有效的 数据 URL 的函数,该函数可以用作图像(或 Favicon!)源。

// Thanks to https://formito.com/tools/favicon
const faviconHref = emoji =>
  `data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 width=%22256%22 height=%22256%22 viewBox=%220 0 100 100%22><text x=%2250%%22 y=%2250%%22 dominant-baseline=%22central%22 text-anchor=%22middle%22 font-size=%2280%22>${emoji}</text></svg>`

这是一个针对 <head> 中的 Favicon <link> 并将其更改为该表情符号的函数。

const changeFavicon = emoji => {
  // Ensure we have access to the document, i.e. we are in the browser.
  if (typeof window === 'undefined') return

  const link =
    window.document.querySelector("link[rel*='icon']") ||
    window.document.createElement("link")
  link.type = "image/svg+xml"
  link.rel = "shortcut icon"
  link.href = faviconHref(emoji)

  window.document.getElementsByTagName("head")[0].appendChild(link)
}

(感谢 这个 StackOverflow 答案 提供了创建链接(如果不存在)的巧妙技巧。)

请随意试一试! 打开 DevTools JavaScript 控制台,复制并粘贴上面的两个函数,并调用 changeFavicon("💃")。 您可以在本网站上直接执行此操作,您会看到 Favicon 更改为那个很棒的跳舞表情符号。

回到我们的时钟/时间项目…… 如果我们想显示带有正确时间的表情符号时钟,我们需要从当前时间确定它。 例如,如果是 10:00,我们想显示 🕙。 如果是 4:30,我们想显示 🕟。 并非每个时间都有表情符号,因此我们将显示我们拥有的最佳表情符号。 例如,在 9:45 到 10:14 之间,我们想显示显示 10:00 的时钟; 从 10:15 到 10:44,我们想显示标记为 10:30 的时钟,等等。

我们可以使用这个函数来实现。

const currentEmoji = () => {
  // Add 15 minutes and round down to closest half hour
  const time = new Date(Date.now() + 15 * 60 * 1000)

  const hours = time.getHours() % 12
  const minutes = time.getMinutes() < 30 ? 0 : 30

  return {
    "0.0": "🕛",
    "0.30": "🕧",
    "1.0": "🕐",
    "1.30": "🕜",
    "2.0": "🕑",
    "2.30": "🕝",
    "3.0": "🕒",
    "3.30": "🕞",
    "4.0": "🕓",
    "4.30": "🕟",
    "5.0": "🕔",
    "5.30": "🕠",
    "6.0": "🕕",
    "6.30": "🕡",
    "7.0": "🕖",
    "7.30": "🕢",
    "8.0": "🕗",
    "8.30": "🕣",
    "9.0": "🕘",
    "9.30": "🕤",
    "10.0": "🕙",
    "10.30": "🕥",
    "11.0": "🕚",
    "11.30": "🕦",
  }[`${hours}.${minutes}`]
}

现在我们只需要每分钟左右调用一次 changeFavicon(currentEmoji())。 如果我们必须使用纯 JavaScript 来完成它,一个简单的 setInterval 将起到作用。

// One minute
const delay = 60 * 1000

// Change the favicon when the page gets loaded...
const emoji = currentEmoji()
changeFavicon(emoji)

// ... and update it every minute
setInterval(() => {
  const emoji = currentEmoji()
  changeFavicon(emoji)
}, delay)

React 部分

由于我的博客由 Gatsby 提供支持,我想能够在 React 组件内部使用此代码,并且尽可能少地进行更改。 它本质上是命令式的,而不是 React 的声明式性质,而且必须每分钟调用一次。 我们该怎么做呢?

Dan Abramov 和 他的精彩博客文章 出现了。 Dan 是一位伟大的作家,他能够以清晰的方式解释复杂的事情,我强烈建议您查看这篇文章,尤其是在您想要更好地了解 React Hooks 的情况下。 您不一定需要理解其中的所有内容——Hooks 的优势之一是即使没有完全理解内部实现,也可以使用它们。 重要的是要知道如何使用它。 以下是如何实现的。

import { useEffect } from "react"
import useInterval from "./useInterval"

const delay = 60 * 1000

const useTimeFavicon = () => {
  // Change the favicon when the component gets mounted...
  useEffect(() => {
    const emoji = currentEmoji()
    changeFavicon(emoji)
  }, [])

  // ... and update it every minute
  useInterval(() => {
    const emoji = currentEmoji()
    changeFavicon(emoji)
  }, delay)
}

最后,只需在根组件中调用 useTimeFavicon(),就可以了! 想看看它的工作原理吗? 这里有一个 部署的 CodePen 项目,您可以在其中看到它,这里有 项目代码 本身。

总结

我们在这里所做的就是将来自三个不同来源的三个代码片段拼凑在一起以获得我们想要的结果。 古罗马人会说Divide et Impera。(我是一名意大利人,所以请容忍我使用一点拉丁语!)。 这意味着“分而治之”。 如果您将任务视为一个整体,您可能会对此感到有些焦虑:“如何在 React 网站上显示始终保持最新状态的当前时间的 Favicon?” 使所有细节都正确并不容易。

好消息是,您并不总是需要在同一时间亲自处理所有细节:将问题分解为子问题要有效得多,如果其中任何问题已经被其他人解决,那就更好了!

听起来像 web 开发,对吧? 使用他人编写的代码没有什么错,只要明智地使用即可。 正如他们所说,没有必要重新发明轮子,而我们在这里得到的是对任何网站的很好增强——无论是显示通知、时间更新还是您能想到的任何内容。