Loading
1867 字
9 分钟
Astro框架Fuwari主题侧边栏添加Umami访问统计
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 部署的思路是一样的)。

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

参考资料#

这篇文章是否对你有帮助?

文章修订历史 (1 次)

查看变更记录
2026-05-09 181fb0c

feat: add git log and blog.bsgun.cn to allowed commands and domains

Astro框架Fuwari主题侧边栏添加Umami访问统计
https://blog.mcxiaochen.top/posts/p614f9cbd/
作者
辰渊尘
发布于
2026-05-09
许可协议
CC BY-NC-SA 4.0