惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

WordPress大学
WordPress大学
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Hacker News: Ask HN
Hacker News: Ask HN
N
News and Events Feed by Topic
Forbes - Security
Forbes - Security
The Last Watchdog
The Last Watchdog
TaoSecurity Blog
TaoSecurity Blog
Schneier on Security
Schneier on Security
SecWiki News
SecWiki News
V
Vulnerabilities – Threatpost
Project Zero
Project Zero
O
OpenAI News
W
WeLiveSecurity
Security Archives - TechRepublic
Security Archives - TechRepublic
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
H
Hacker News: Front Page
Cisco Talos Blog
Cisco Talos Blog
Spread Privacy
Spread Privacy
Help Net Security
Help Net Security
P
Privacy & Cybersecurity Law Blog
K
Kaspersky official blog
S
Security @ Cisco Blogs
Latest news
Latest news
AWS News Blog
AWS News Blog
U
Unit 42
Martin Fowler
Martin Fowler
阮一峰的网络日志
阮一峰的网络日志
S
Secure Thoughts
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Know Your Adversary
Know Your Adversary
Scott Helme
Scott Helme
博客园 - 司徒正美
B
Blog RSS Feed
C
Check Point Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
D
Docker
Google Online Security Blog
Google Online Security Blog
Jina AI
Jina AI
aimingoo的专栏
aimingoo的专栏
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Last Week in AI
Last Week in AI
月光博客
月光博客
C
CXSECURITY Database RSS Feed - CXSecurity.com
S
SegmentFault 最新的问题
NISL@THU
NISL@THU
T
The Blog of Author Tim Ferriss
C
Cisco Blogs
Attack and Defense Labs
Attack and Defense Labs
小众软件
小众软件

辰渊尘站

713解锁节来辣!小米17全系,k90pm又能解bl了 - 辰渊尘站 服务器面板迁移:从宝塔到 1Panel - 辰渊尘站 Subconverter 太臃肿?PHP 版轻量化替代来了! - 辰渊尘站 Astro框架Fuwari主题侧边栏添加Umami访问统计 为Fuwari框架适配友链状态显示 为Fuwari框架适配友链状态显示 免费领取网易云音乐7天会员 免费领取网易云音乐7天会员 小米MiMo Token Plan免费送辣! 小米MiMo Token Plan免费送辣! Astro框架Fuwari主题实现仿hexo-abbrlink功能 Astro框架Fuwari主题实现仿hexo-abbrlink功能 观《鬼灭之刃:无限城篇 第一章 猗窝座再袭》首映有感 观《鬼灭之刃:无限城篇 第一章 猗窝座再袭》首映有感 为你anzhiyu主题的Twikoo评论系统恢复预览按钮 为你anzhiyu主题的Twikoo评论系统恢复预览按钮 山东泰安泰山游记:煌煌泰山景,谦谦君子风 山东泰安泰山游记:煌煌泰山景,谦谦君子风 安知鱼主题:修复背景图修改引发的深色模式可读性问题 安知鱼主题:修复背景图修改引发的深色模式可读性问题 安知鱼主题实现友链状态前端显示 安知鱼主题实现友链状态前端显示 我敲!优选DNS牛大了 我敲!优选DNS牛大了 安知鱼主题侧边栏添加无聊湾 安知鱼主题侧边栏添加无聊湾 从零开始使用Hexo框架搭建属于你的博客(一)环境准备篇 从零开始使用Hexo框架搭建属于你的博客(一)环境准备篇 记录下Hexo博客从本地构建迁移到Netlify,AI API Key 泄露问题与解决方案记录 记录下Hexo博客从本地构建迁移到Netlify,AI API Key 泄露问题与解决方案记录 云服务器宝塔部署Twikoo博客评论系统 云服务器宝塔部署Twikoo博客评论系统 手把手教你在Linux系统下部署MCSManager并搭建一个MC服务器 手把手教你在Linux系统下部署MCSManager并搭建一个MC服务器 为你的Twikoo添加酷安表情包 为你的Twikoo添加酷安表情包 记录一次博客评论迁移过程 记录一次博客评论迁移过程 记一次花嫁联名借记卡申领过程 记一次花嫁联名借记卡申领过程 为使用anzhiyu主题的博客加上十年之约进度条 为使用anzhiyu主题的博客加上十年之约进度条 有关建站一个月以来的一点点感想和后续计划 有关建站一个月以来的一点点感想和后续计划 这可能是iOS自签的版本答案,二合一LiveContainer教程来辣! 这可能是iOS自签的版本答案,二合一LiveContainer教程来辣! iOS侧载新选择!SideStore+LiveContainer,纯净无广,无限安装软件!!! iOS侧载新选择!SideStore+LiveContainer,纯净无广,无限安装软件!!! 从零开始使用Hexo框架搭建属于你的博客(零)准备篇 从零开始使用Hexo框架搭建属于你的博客(零)准备篇 Arch Linux+Hyprland从安装到使用只需这一篇(保姆级喂饭超全教程) Arch Linux+Hyprland从安装到使用只需这一篇(保姆级喂饭超全教程) - 辰渊尘站 恭喜你找到了本站的第一篇文档 恭喜你找到了本站的第一篇文档 - 辰渊尘站
Astro框架Fuwari主题侧边栏添加Umami访问统计
辰渊尘 · 2026-05-09 · via 辰渊尘站
TIP

修改前必读:

  • 本帖基于 Astro框架Fuwari主题 进行修改方案编写,因此请读者优先掌握 Astro Docs 的内容后再来进行魔改。
  • 由于修改内容较多,以及可能会导致意料之外的事情,推荐使用 Github 配合 VSCode 进行修改,方便随时备份恢复

前言#

之前一直想在侧边栏加一个访问统计的功能,看了不少教程发现大部分都是基于不蒜子或者 vercount 的,偶然间发现了通过 Umami + PHP 搭配实现的方式,觉得不错就搞了一下,最终效果就是在侧边栏展示了 当前在线、今日访客、今日浏览、昨日浏览、本月浏览、总浏览 这些数据,这篇文章就来分享一下怎么实现的。

本文参考了 梦爱吃鱼佬的文章 并在其基础上做了一些扩展,感谢原作者的分享!

效果预览#

侧边栏会多出一个统计区域,分为三行两列展示:

数据通过前端 JS 从 PHP 接口获取,每次页面加载时自动更新。

需要的东西#

  • 一个已经部署好的 Umami 实例(自建或者用别人的都行)
  • 一个能跑 PHP 的 服务器(宝塔、虚拟主机之类的都行)
  • 你的博客是基于 Astro + Fuwari主题

原理说明#

整个流程其实很简单:

  1. Umami 负责收集你博客的访问数据
  2. PHP 文件 作为中间层,调用 Umami 的 API 获取统计数据,然后以 JSON 格式返回给前端
  3. 前端 JS 请求 PHP 文件的地址,拿到数据后渲染到侧边栏

为什么要加一层 PHP?因为 Umami 的 API 需要 Token 认证,直接在前端调用会暴露 Token,所以用 PHP 做一层代理。

步骤一:获取 Umami API 文件#

以前获取 Token 需要用 Hoppscotch 手动调 API,比较麻烦。现在梦爱吃鱼佬做了一个在线工具,一键搞定。

打开 Umami API 生成工具,依次填入:

  • 你的 Umami 服务地址
  • 你的 Umami 账号和密码
  • 选择你要统计的 网站

工具会自动登录获取 Token、拉取网站列表,完全不用手动调 API。确认数据无误后,点击 导出 API 文件,会下载一个 PHP 文件。

这个工具不会保存任何数据到远程服务器,所有信息仅存储在你的浏览器本地,可以放心使用

步骤二:部署 PHP 文件#

把下载的 PHP 文件上传到你的服务器,确保能通过域名访问到就行。如果你用的是宝塔,直接丢到网站根目录即可。

访问这个 PHP 文件的地址,如果返回类似这样的 JSON 就说明成功了:

{

"today_uv": 42,

"today_pv": 121,

"online_users": 0,

"yesterday_uv": 68,

"yesterday_pv": 203,

"last_month_pv": 7429,

"last_year_pv": 19553,

"total_uv": 3652,

"total_pv": 19553

}

到这里,后端部分就搞定了,记下这个 PHP 文件的访问地址,后面前端要用。

WARNING

PHP 文件里包含了你的 Umami Token,记得不要把这个文件的源码泄露出去了

步骤三:添加前端代码#

创建 JS 文件#

public/js/ 目录下创建 umami-status.js

const API_URL = "https://你的php文件地址/umami-api.php";

async function loadUmamiStats() {

try {

const res = await fetch(API_URL, { cache: "no-store" });

const data = await res.json();

function set(id, value) {

const el = document.getElementById(id);

if (el) el.textContent = value ?? 0;

}

set("stat-online", data.online_users);

set("stat-uv", data.today_uv);

set("stat-today-pv", data.today_pv);

set("stat-yesterday-pv", data.yesterday_pv);

set("stat-month-pv", data.last_month_pv ?? 0);

set("stat-total-pv", data.total_pv);

} catch (err) {

console.error("Umami API Error:", err);

}

}

/* 首次加载 */

document.addEventListener("DOMContentLoaded", loadUmamiStats);

/* Astro 页面切换后重新执行 */

document.addEventListener("astro:page-load", loadUmamiStats);

cache: "no-store" 确保每次都获取最新数据,不会被浏览器缓存。astro:page-load 事件是 Fuwari 主题用的 Swup 页面过渡库提供的,确保 SPA 路由切换后统计数据也能刷新

引入 JS 文件#

修改 src/layouts/Layout.astro,在 <head> 中加入:

<script type="module" src="/js/umami-status.js"></script>

修改侧边栏组件#

修改 src/components/widget/Profile.astro,在社交链接区域(</div> 闭合 flex-wrap 那个 div)后面添加统计区域:

<!-- 全站访问统计 -->

<div class="grid grid-cols-2 mt-3 pt-3 border-t border-neutral-300 dark:border-neutral-700 gap-y-3">

<div class="text-center">

<div class="text-xs text-neutral-500 mb-1 flex items-center justify-center gap-1">

<span class="text-xs">当前在线</span>

</div>

<div id="stat-online" class="font-bold text-lg text-neutral-700 dark:text-neutral-300 umami-soft">

<span>0</span>

</div>

</div>

<div class="text-center border-l border-neutral-300 dark:border-neutral-700">

<div class="text-xs text-neutral-500 mb-1 flex items-center justify-center gap-1">

<span class="text-xs">今日访客</span>

</div>

<div id="stat-uv" class="font-bold text-lg text-neutral-700 dark:text-neutral-300 umami-soft">

<span>0</span>

</div>

</div>

</div>

<div class="grid grid-cols-2 mt-3 pt-3 border-t border-neutral-300 dark:border-neutral-700 gap-y-3">

<div class="text-center border-neutral-300 dark:border-neutral-700 ">

<div class="text-xs text-neutral-500 mb-1 flex items-center justify-center gap-1">

<span class="text-xs">今日浏览</span>

</div>

<div id="stat-today-pv" class="font-bold text-lg text-neutral-700 dark:text-neutral-300 umami-soft">

<span>0</span>

</div>

</div>

<div class="text-center border-l border-neutral-300 dark:border-neutral-700">

<div class="text-xs text-neutral-500 mb-1 flex items-center justify-center gap-1">

<span class="text-xs">昨日浏览</span>

</div>

<div id="stat-yesterday-pv" class="font-bold text-lg text-neutral-700 dark:text-neutral-300 umami-soft">

<span>0</span>

</div>

</div>

</div>

<div class="grid grid-cols-2 mt-3 pt-3 border-t border-neutral-300 dark:border-neutral-700 gap-y-3">

<div class="text-center border-neutral-300 dark:border-neutral-700">

<div class="text-xs text-neutral-500 mb-1 flex items-center justify-center gap-1">

<span class="text-xs">本月浏览</span>

</div>

<div id="stat-month-pv" class="font-bold text-lg text-neutral-700 dark:text-neutral-300 umami-soft">

<span>0</span>

</div>

</div>

<div class="text-center border-l border-neutral-300 dark:border-neutral-700">

<div class="text-xs text-neutral-500 mb-1 flex items-center justify-center gap-1">

<span class="text-xs">总浏览</span>

</div>

<div id="stat-total-pv" class="font-bold text-lg text-neutral-700 dark:text-neutral-300 umami-soft">

<span>0</span>

</div>

</div>

</div>

这段代码的结构是三个 grid-cols-2 的 grid 容器,每个容器放两个统计项,用 border-t 做分隔线。id 和 JS 里的 set() 函数对应,数据加载完成后会自动替换掉默认的 0

进阶:加上数字滚动动画#

如果你觉得数字直接跳变太生硬,可以加一个简单的数字滚动效果。

src/styles/main.css(或者你喜欢的地方)加上:

.umami-soft span {

display: inline-block;

transition: all 0.3s ease;

}

然后把 JS 里的 set 函数改成带动画的版本:

function set(id, value) {

const el = document.getElementById(id);

if (!el) return;

const span = el.querySelector('span');

if (!span) return;

const target = parseInt(value) || 0;

const current = parseInt(span.textContent) || 0;

if (current === target) return;

const duration = 600;

const startTime = performance.now();

function animate(currentTime) {

const elapsed = currentTime - startTime;

const progress = Math.min(elapsed / duration, 1);

// easeOutCubic

const eased = 1 - Math.pow(1 - progress, 3);

const currentVal = Math.round(current + (target - current) * eased);

span.textContent = currentVal;

if (progress < 1) {

requestAnimationFrame(animate);

}

}

requestAnimationFrame(animate);

}

这样数字就会从当前值平滑过渡到目标值,视觉效果好很多。

常见问题#

数据全是 0 怎么办?#

  1. 检查 PHP 文件是否正常返回 JSON,直接访问 PHP 文件地址看看
  2. 检查 umami-status.js 里的 API_URL 是否正确
  3. 打开浏览器 F12 控制台看有没有报错
  4. 确认 Umami 确实在正常收集数据

在线人数不准确?#

Umami 的 /active 接口返回的是最近 5 分钟内的活跃用户数,本身就是一个近似值,不用太纠结精确度。

想自定义显示哪些统计项?#

很简单,你只需要:

  1. 在 PHP 文件里返回你想要的字段
  2. Profile.astro 里加对应的 HTML
  3. umami-status.js 里加对应的 set() 调用

三步对应上就行,想加什么加什么。

写在最后#

整个实现其实不复杂,核心就是 Umami + PHP + 前端三件套,PHP 做中转解决了 Token 安全问题,前端 JS 负责渲染,改一改侧边栏组件就完事了。

如果你不想自己搭 Umami,也可以用别人公共的实例,但要注意数据隐私问题。自建的话推荐用 Docker 一键部署,配合宝塔管理很方便,可以参考我之前写的 宝塔部署教程(虽然那篇是讲 Twikoo 的,但 Docker 部署的思路是一样的)。

以上就是全部内容了,有问题评论区见!

参考资料#