前几天我发现了这个 免费 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 开发,对吧? 使用他人编写的代码没有什么错,只要明智地使用即可。 正如他们所说,没有必要重新发明轮子,而我们在这里得到的是对任何网站的很好增强——无论是显示通知、时间更新还是您能想到的任何内容。
这应该使用
~=
而不是*=
。*=
将匹配任何包含“icon”字符的内容,例如apple-touch-icon
; 但~=
用于匹配以空格分隔的令牌列表,如class
和rel
。同样关于这个话题,
shortcut icon
是来自旧版 IE 的过时用法,它根本不支持 SVG 或动态 Favicon; 所以你也可以直接写icon
。(我刚刚彻底修改了来自此 Stack Overflow 答案的内容。)
嘿,Carlo,使用对象文字而不是 switch 语句或无休止的 if-elses 太棒了。 您的代码非常干净且易于理解。 我喜欢使用 useEffect 和 useInterval React Hooks 的实现!
我绝对可以想象自己使用类似的东西,至少用 useEffect 调用替换静态 favicon.ico!
这是我见过的最糟糕最糟糕最糟糕最糟糕最糟糕的功能,它对可用性造成了影响。
听起来你只是在互联网上闲逛了一小段时间。
最好避免使用不必要的冗长代码,例如
可以改写为
changeFavicon
不会每次都添加一个新的链接,而是替换当前链接吗?我之前编写了一个 React 钩子来更新 Favicon。 它包含将画布转换为 Favicon 的 href 的函数。 并且它有一个函数可以设置表情符号 SVG Favicon,就像这篇文章一样。 如果有人有兴趣,我已经在 GitHub 上发布了它 https://github.com/JulesBlm/useFavicon 查看演示页面 https://jules.engineer/usefavicon。