Rewards - 一个高度可定制的赞赏展示页 为您的 Hexo 博客打造专属的动态赞赏墙

作为一名博主,我们收到的每一份赞赏都凝聚着读者的心意与支持。但手动更新静态的感谢名单不仅繁琐,也缺乏时效性。现在,有了一个更优雅、更自动化的解决方案——Rewards 项目,一个专为个人博客打造的动态赞赏墙。

这不仅仅是一个简单的展示页,利用 Cloudflare Pages 实现全球极速分发,并借助 KV 存储提供高效、低成本的数据读写。最重要的是,它实现了彻底的“配置即代码”,您可以通过简单的环境变量设置,轻松定制页面的每一个细节,而无需触碰一行代码。

本篇文章将作为一份详尽的指南,带您完成两项核心任务:

  • 从零开始,在 Cloudflare 上成功部署您自己的 Rewards 赞赏页。
  • 手把手教您如何将这个动态赞赏墙无缝集成到您的 Hexo Solitude 主题博客的“关于”页面中。

Rewards - 一个高度可定制的赞赏展示页

这是一个基于 Cloudflare Pages 和 KV 存储构建的、轻量级、高度可定制的赞赏记录展示页面。它允许您轻松地展示收到的赞赏,并通过环境变量进行全方位的个性化配置,无需修改任何代码。

在线体验

前端展示:https://rewards.zrfme.com
后端提交:https://rewards.zrfme.com/admin

界面预览

前端展示截图
后台提交截图

功能特性

  • 🚀 Serverless 架构:完全托管在 Cloudflare 的全球网络上,无需自己的服务器。
  • ⚡️ 极速访问:得益于 Cloudflare Pages 的静态站点优化和 CDN 加速。
  • 📦 KV 数据存储:使用 Cloudflare KV 作为数据库,读写速度快,成本极低。
  • 🎨 高度可定制:从背景图片、标题、二维码到分页数量、高亮金额,几乎所有内容都可以通过环境变量进行配置。
  • 📱 响应式设计:在桌面和移动设备上都有良好的视觉效果。
  • 🔒 安全后台:提供一个独立的 /admin 页面,通过密码保护来提交新的赞赏记录。
  • 🌟 金额高亮:可以自定义金额阈值,为“大额”赞赏提供特殊颜色高亮。
  • 📄 自动分页:当赞赏记录过多时,自动生成分页导航。
  • 💨 平滑加载:优雅的加载动画和内容淡入效果,提升用户体验。

部署指南

第一步:获取代码

首先打开 https://github.com/shaoyouvip/Rewards 点击项目页面右上角 Starred(求个星星!!!) 然后点击 Fork 按钮,将此项目复制到您自己的 GitHub 仓库中。

Fork 项目
Fork 项目

第二步:创建 KV 命名空间

  1. 打开 https://dash.cloudflare.com/ 登录到您的 Cloudflare 账户。
  2. 在左侧菜单中,进入 存储和数据库 -> KV
    创建KV命名空间
  3. 点击 创建命名空间,为您的命名空间取一个名字,例如 REWARDS_KV,然后点击创建。
    创建KV命名空间

第三步:在 Cloudflare Pages 中创建项目

  1. 在 Cloudflare 仪表板中,进入 Workers 和 Pages -> Pages 选项卡。
    构建
  2. 点击 创建项目 -> Pages -> 导入现有 Git 存储库
    构建
  3. 选择您刚刚 Fork 的 GitHub 仓库。
    构建
  4. 在“设置构建和部署”页面,填写以下信息:
    • 构建命令 (Build command): (留空,不需要任何命令)
    • 构建输出目录 (Build output directory): public
    • 点击“保存并部署”。
      构建

第四步:绑定 KV 和设置环境变量

  1. 等待第一次部署完成后,点击下方的继续按钮,进入您刚刚创建的 Pages 项目的控制台。
  2. 点击 设置 -> 绑定 -> KV 命名空间
    绑定 KV
  3. 点击 添加绑定
    • 变量名称REWARDS_KV
    • KV 命名空间:选择您在第二步中创建的 REWARDS_KV
    • 点击 保存
      KV 命名空间
  4. 现在,进入 设置 -> 环境变量,在这里配置您的个性化信息。这是最关键的一步!
    • 点击 添加变量,然后根据下面的“配置说明”添加您需要的变量。必须设置 FORM_SECRET 以及您自己的收款码链接!变量参考下方详细说明
      添加变量
  5. 完成变量设置后,回到项目的部署页面,点击重新部署最新的版本。

恭喜! 您的专属赞赏页面现在已经部署完成了。

⚙️ 配置说明 (环境变量)

您可以通过在 Cloudflare Pages 项目的 设置 -> 环境变量 中添加以下变量来自定义您的页面。必须至少配置前三项。

变量名称 说明 默认值
FORM_SECRET (必须) 访问 /admin 页面提交记录时所需的密码。
CONFIG_QR_WECHAT (必须) 您的微信收款二维码图片链接。 您的二维码链接
CONFIG_QR_ALIPAY (必须) 您的支付宝收款二维码图片链接。 您的二维码链接
CONFIG_PAGE_TITLE 浏览器标签页上显示的标题。 周润发的赞赏页面
CONFIG_BANNER_TITLE 页面顶部大标题下的副标题。 您的赞赏,是我的续命咖啡~
CONFIG_BACKGROUND_IMAGE_URL 整个页面的背景图片链接。 /img/bj.webp (项目内图片)
CONFIG_FAVICON 浏览器标签页上显示的图标链接。 /img/icon.webp (项目内图片)
CONFIG_INFO_TEXT 页面底部信息框中的提示文字。 如需修改昵称信息...
CONFIG_INFO_EMAIL 页面底部信息框中显示的联系邮箱。 zrf@zrf.me
CONFIG_FOOTER_HTML 最底部的版权信息,支持 HTML。 周润发: <a href="https://d.zrf.me/blog">博客</a>
CONFIG_ROWS_PER_PAGE 每页显示的赞赏记录数,默认为10量。 10
CONFIG_HIGHLIGHT_PRIMARY 主要高亮(红色)的金额门槛。 100
CONFIG_HIGHLIGHT_SECONDARY 次要高亮(黄色)的金额门槛。 20

✍️ 如何使用

部署完成后,您可以通过以下链接访问您的赞赏页:

  • 主页: https://你的项目地址
    • 说明:这是公开的赞赏展示页面,所有人都可以访问查看。
  • 后台: https://你的项目地址/admin
    • 说明:这是用于手动添加赞赏记录的后台页面,需要输入密码才能提交。
  • JSON数据: https://你的项目地址/api/rewards
    • 说明:这是一个公开的 API 链接,它会以 JSON 格式返回所有赞赏数据。您可以将此链接用于其他项目或进行二次开发。

后台提交说明

访问 https://你的项目地址/admin 提交页面后,您需要填写以下信息:

  • 赞赏者名字: (必需) 填写赞赏者的昵称。
  • 金额: (必需) 填写收到的具体金额。
  • 提交时间 (可选): 如果留空,系统会自动记录为当前时间。您也可以点击选择一个过去的时间点进行补录。
  • 提交密码: (必需) 输入您在 Cloudflare 环境变量 FORM_SECRET 中设置的密码。

填写完毕后,点击“提交”按钮即可。

Solitude主题博客 接入赞赏页

本教程将指导您如何将 Rewards 赞赏页无缝集成到您的 Hexo Solitude 主题博客中,实现一个从 API 动态更新的赞赏墙。

  • 提示: 这个方法理论上也适用于其他类似主题(如安知鱼),只需根据您的主题文件结构稍作调整即可。

文件修改概览

在开始之前,请熟悉我们即将修改的几个核心文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
.
├── _config.solitude.yml # 主题配置文件
├── source/
│ ├── _data/
│ │ └── about.yml # “关于”页面的数据文件
│ └── about/
│ └── index.md # “关于”页面的内容文件
└── themes/
└── solitude/
└── layout/
└── includes/
└── page/
└── about.pug # “关于”页面的布局模板

第一部分:优化文章底部的“赞赏名单”链接

此步骤旨在让您每篇文章底部的“赞赏作者”弹窗,可以正确链接到我们刚刚部署好的独立赞赏页面。

  1. 我们需要更改的地方有博客文章页面底部 赞赏作者 这个按钮的 赞赏名单 页面。
    文章底部的赞赏弹窗

  2. 打开博客路径: _config.solitude.yml 搜索 打赏Reward 关键词,找到如下配置把你的 赞赏名单 替换为你部署好的页面网址即可,如下图。
    修改主题配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Reward
# 打赏
award:
enable: true
appreciators: https://rewards.zrf.me/ # 赞赏名单地址
# Reward Title
# 打赏标题
title: 感谢您的赞赏 #Thanks for your appreciation. /
desc: 由于您的支持,我才能够实现写作的价值。 #Because of your support, I realize the value of writing articles. / 由于您的支持,我才能够实现写作的价值。
# Reward list
# 打赏列表
list:
- name: 微信
qcode: /img/zsm_wx.webp
url: /img/zsm_wx.webp
color: var(--efu-black)
- name: 支付宝
qcode: /img/zsm_zfb.webp
url: /img/zsm_zfb.webp
color: var(--efu-black)

第二部分:在“关于”页面创建动态赞赏列表

此步骤将在您的“关于”页面创建一个从 API 实时拉取数据的赞赏墙,并带有30分钟的浏览器缓存。

步骤 1:向 index.md 注入核心脚本

  1. 打开博客路径: source\about\index.md 复制下方代码进去,赞赏API改为你自己的, 格式: https://你的项目地址/api/rewards ,如下图。
    向 `index.md` 注入核心脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
<script>
function loadRewardList() {
const apiUrl = "https://rewards.zrf.me/api/rewards"; // 赞赏API
const cacheKey = "rewardListCache";
const cacheTimeKey = "rewardListCacheTime";
const cacheTTL = 30 * 60 * 1000; // 30分钟
const rewardListContainer = document.querySelector(".reward-list-all");
const totalAmountContainer = document.querySelector(".reward-list-tips p");

function formatTime(dateStr) {
const date = new Date(dateStr);
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
}

function createRewardItem({ name, money, date }) {
const item = document.createElement("div");
item.className = "reward-list-item";
const nameDiv = document.createElement("div");
nameDiv.className = "reward-list-item-name";
nameDiv.textContent = name;
const bottomGroup = document.createElement("div");
bottomGroup.className = "reward-list-bottom-group";
const moneyDiv = document.createElement("div");
moneyDiv.className = "reward-list-item-money";
moneyDiv.innerHTML = ${money}`;
moneyDiv.style.backgroundColor = "undefined";
const time = document.createElement("time");
time.className = "datetime reward-list-item-time";
time.setAttribute("datetime", new Date(date).toISOString());
time.style.display = "inline";
time.textContent = formatTime(date);
bottomGroup.appendChild(moneyDiv);
bottomGroup.appendChild(time);
item.appendChild(nameDiv);
item.appendChild(bottomGroup);
return item;
}

function renderList(rewards) {
const allItems = rewardListContainer.children;
const lastButton = allItems[allItems.length - 1];
rewardListContainer.innerHTML = "";
let total = 0;
rewards.forEach(entry => {
total += Number(entry.money || 0);
rewardListContainer.appendChild(createRewardItem(entry));
});
rewardListContainer.appendChild(lastButton);
totalAmountContainer.textContent = `总金额:¥ ${total.toFixed(2)},将全部用于博客的维护和更新。`;
}

function isCacheValid() {
const timestamp = localStorage.getItem(cacheTimeKey);
if (!timestamp) return false;
return Date.now() - Number(timestamp) < cacheTTL;
}

if (isCacheValid()) {
try {
const cachedData = JSON.parse(localStorage.getItem(cacheKey));
if (Array.isArray(cachedData)) {
renderList(cachedData);
return;
}
} catch (e) {
console.warn("缓存解析失败,尝试重新请求 API");
}
}

fetch(apiUrl)
.then(res => res.json())
.then(json => {
const rewards = json.data || [];
renderList(rewards);
localStorage.setItem(cacheKey, JSON.stringify(rewards));
localStorage.setItem(cacheTimeKey, Date.now().toString());
})
.catch(err => {
console.error("读取赞赏数据失败:", err);
});
}
loadRewardList();
</script>

步骤 2:修改 about.pug 布局

此步骤是为了让 index.md 中注入的脚本能够被正确渲染到页面上。

  1. 打开博客路径: themes\solitude\layout\includes\page\about.pug 在最下方添加一个 != page.content 与上方 include 保持一样的缩进,如下图。
    修改 `about.pug` 布局
1
2
3
4
5
6
7
8
9
10
11
12
if site.data.about
#about-page
include ../widgets/page/about/authorinfo
include ../widgets/page/about/contentinfo
include ../widgets/page/about/skillsinfo
include ../widgets/page/about/personalities
include ../widgets/page/about/motto
include ../widgets/page/about/hobbies
include ../widgets/page/about/other
include ../widgets/page/about/tenyear
include ../widgets/page/about/award
!= page.content

步骤 3:配置 about.yml 占位符

此步骤为赞赏卡片提供基础的静态内容和加载时的占位符,以优化用户体验。

  1. 打开博客路径:source_data\about.yml 拉到最下方找到 打赏列表 替换下方代码进去把原有的覆盖,如下图。
    配置 about.yml 占位符
1
2
3
4
5
6
7
8
9
# 打赏列表
award:
enable: true
description: 感谢赞赏的人,因为你们,让我感受到写博客这件事情能够给你们创造了价值。这会让我在这条路上走得更远。
tips: 总金额:¥ {sum},将全部用于博客的维护和更新。 # 必须带 {sum},否则无法显示总金额
rewardList: # 底部捐赠
- name: 赞赏数据加载中
money: 0
time: 2025-01-01

完成以上所有步骤并重新部署您的 Hexo 博客后,您就拥有了一个功能强大、外观精美且完全自动化的赞赏系统!

特别鸣谢