Hugo Stack 主题页脚统计和访问量集成

记录 Hugo Stack 主题的页脚统计功能(文章统计、运行时间)和 busuanzi 访问量统计集成

Hugo Stack 主题页脚统计和访问量集成

本文详细记录 Hugo Stack 主题的页脚统计功能(文章统计、运行时间统计)和 busuanzi 访问量统计的集成方法。

概述

本次集成主要涉及三个方面:

  1. 文章统计:显示文章总数和总字数(格式:x 万 x 千字)
  2. 运行时间统计:显示网站运行时间(格式:x 年 x 月 x 天),起始时间为第一篇文章的发布日期
  3. busuanzi 访问量统计:集成不蒜子统计,显示站点访问量、访客数和文章阅读量

1. 页脚统计功能

1.1 需求说明

在页脚添加两个统计功能:

  1. 文章统计:显示文章总数和总字数(格式:x 万 x 千字)
  2. 运行时间统计:显示网站运行时间(格式:x 年 x 月 x 天),起始时间为第一篇文章的发布日期

1.2 配置说明

themes/hugo-theme-stack/hugo.yamlfooter 字段中添加两个开关:

params:
    footer:
        since: 2010
        customText: <a href="https://beian.miit.gov.cn/" target="_blank" rel="noopener" >陕ICP备20000710号</a>
        showStats: true      # 文章统计开关
        showRuntime: true    # 运行时间统计开关

配置项说明

  • showStats: 控制是否显示文章统计(文章数和总字数)
  • showRuntime: 控制是否显示运行时间统计
  • 两个开关独立控制,可以单独启用或禁用

1.3 实现方案

修改 themes/hugo-theme-stack/layouts/partials/footer/footer.html 文件,在 customText 之后添加统计功能:

{{ with .Site.Params.footer.customText }}
    {{ . | safeHTML }} <br/>
{{ end }}

{{ if .Site.Params.footer.showRuntime }}
    {{ $posts := where .Site.RegularPages "Section" "post" }}
    {{ if $posts }}
        {{ $firstPost := index (sort $posts "Date" "asc") 0 }}
        {{ $startDate := $firstPost.Date }}
        {{ $now := now }}
        {{ $totalSeconds := sub $now.Unix $startDate.Unix }}
        {{ $totalDays := div $totalSeconds 86400 }}
        {{ $years := div $totalDays 365 }}
        {{ $remainingDays := mod $totalDays 365 }}
        {{ $months := div $remainingDays 30 }}
        {{ $days := mod $remainingDays 30 }}
        本站已运行{{ $years }}年{{ $months }}月{{ $days }}天
        <br/>
    {{ end }}
{{ end }}

{{ if .Site.Params.footer.showStats }}
    {{ $scratch := newScratch }}
    {{ range (where .Site.Pages "Kind" "page" )}}
        {{ $scratch.Add "total" .WordCount }}
    {{ end }}
    {{ $totalWords := $scratch.Get "total" }}
    {{ $tenThousands := div $totalWords 10000 }}
    {{ $remainingThousands := mod (div $totalWords 1000) 10 }}
    发表了{{ len (where .Site.RegularPages "Section" "post") }}篇文章 ·
    总计{{ $tenThousands }}万{{ $remainingThousands }}千字
    <br/>
{{ end }}

1.4 功能说明

1.4.1 运行时间统计(showRuntime)

实现逻辑

  1. 获取所有 post 分区的文章:where .Site.RegularPages "Section" "post"
  2. 按发布日期升序排序:sort $posts "Date" "asc"
  3. 获取第一篇文章:index ... 0
  4. 使用第一篇文章的发布日期作为起始时间:$firstPost.Date
  5. 计算与当前日期的差值,转换为年、月、天

显示格式

  • 本站已运行X年X月X天
  • 如果没有文章,则不显示

计算方式

  • 使用 Unix 时间戳计算总秒数
  • 转换为总天数(86400 秒 = 1 天)
  • 年数 = 总天数 ÷ 365
  • 剩余天数 = 总天数 % 365
  • 月数 = 剩余天数 ÷ 30
  • 天数 = 剩余天数 % 30

1.4.2 文章统计(showStats)

实现逻辑

  1. 遍历所有页面(where .Site.Pages "Kind" "page"
  2. 累加所有页面的字数(WordCount
  3. 统计 post 分区的文章数量
  4. 将总字数格式化为"万"和"千"单位

显示格式

  • 发表了X篇文章 · 总计X万X千字

字数格式化

  • 万位数 = 总字数 ÷ 10000
  • 千位数 = (总字数 ÷ 1000) % 10

示例

  • 如果总字数为 12345,则显示:总计1万2千字
  • 如果总字数为 56789,则显示:总计5万6千字

1.5 显示位置

统计信息显示在页脚的 powerby 部分,顺序为:

  1. customText(自定义文本,如备案信息)
  2. showRuntime(运行时间统计)
  3. showStats(文章统计)
  4. 主题信息(Built with Hugo, Designed by Jimmy)

1.6 使用示例

启用所有统计功能

params:
    footer:
        showStats: true
        showRuntime: true

只启用文章统计

params:
    footer:
        showStats: true
        showRuntime: false

只启用运行时间统计

params:
    footer:
        showStats: false
        showRuntime: true

禁用所有统计功能

params:
    footer:
        showStats: false
        showRuntime: false

1.7 注意事项

  1. 运行时间统计

    • 如果没有文章,运行时间统计不会显示
    • 起始时间自动使用第一篇文章的发布日期,无需手动配置
  2. 文章统计

    • 统计所有页面的字数(包括非文章页面)
    • 只统计 post 分区的文章数量
  3. 性能考虑

    • 统计功能在构建时计算,不影响运行时性能
    • 使用 newScratch 进行累加计算,效率较高

2. busuanzi 访问量统计集成

2.1 需求说明

集成不蒜子(busuanzi)统计服务,实现:

  1. 站点统计:在页脚显示总访问量和总访客数
  2. 文章统计:在文章详情页显示文章阅读量
  3. 数字格式化:大于 1000 的数字自动转换为 k 格式(如 1500 → 1.5k)

2.2 配置说明

themes/hugo-theme-stack/hugo.yaml 中添加 busuanzi 配置:

params:
    busuanzi:
        enabled: true
        article:
            enabled: true
        footer:
            enabled: true

配置项说明

  • busuanzi.enabled: 总开关,控制是否启用 busuanzi
  • busuanzi.article.enabled: 控制文章页是否显示访问量
  • busuanzi.footer.enabled: 控制页脚是否显示站点统计

2.3 实现方案

2.3.1 加载 busuanzi 脚本

创建 layouts/partials/google_analytics.html 文件:

{{ if .Site.Params.busuanzi.enabled }}
<script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
{{ end }}

2.3.2 页脚站点统计

修改 themes/hugo-theme-stack/layouts/partials/footer/footer.html,在 showStats 之后添加:

{{ if and .Site.Params.busuanzi.enabled .Site.Params.busuanzi.footer.enabled }}
    总访问量<span id="busuanzi_value_site_pv">0</span>次,总访客数<span id="busuanzi_value_site_uv">0</span>    <br/>
{{ end }}

2.3.3 文章访问量显示

修改 themes/hugo-theme-stack/layouts/partials/article/components/details.html,在 article-time footer 中添加:

{{- if and .Site.Params.busuanzi.enabled .Site.Params.busuanzi.article.enabled -}}
    <div class="article-views" style="display: none;">
        <span id="busuanzi_value_page_pv">0</span> 次阅读
    </div>
{{- end -}}

2.3.4 数字格式化脚本

修改 themes/hugo-theme-stack/layouts/partials/footer/components/script.html,添加格式化脚本:

{{- if .Site.Params.busuanzi.enabled -}}
<script>
// 格式化数字,大于1000显示为k
(function() {
    function formatBusuanzi(value) {
        if (!value) return '0';
        // 如果已经是格式化后的值(包含k),直接返回
        if (value.toString().includes('k')) return value;
        var num = parseInt(value);
        if (isNaN(num)) return value;
        if (num >= 1000) {
            return (num / 1000).toFixed(1) + 'k';
        }
        return num.toString();
    }

    // 格式化单个元素
    function formatElement(elementId) {
        var element = document.getElementById(elementId);
        if (!element) return;
        
        // 检查是否已经格式化过(通过 data-formatted 属性)
        if (element.hasAttribute('data-formatted')) {
            return;
        }
        
        var originalText = element.textContent.trim();
        // 只处理纯数字,且不是0(0可能是初始值,需要等待 busuanzi 更新)
        if (originalText && /^\d+$/.test(originalText) && originalText !== '0') {
            var formatted = formatBusuanzi(originalText);
            if (formatted !== originalText) {
                element.textContent = formatted;
                element.setAttribute('data-formatted', 'true');
                // 显示元素(如果之前是隐藏的)
                if (element.style.display === 'none') {
                    element.style.display = '';
                }
            } else {
                element.setAttribute('data-formatted', 'true');
                if (element.style.display === 'none') {
                    element.style.display = '';
                }
            }
        } else if (originalText === '0') {
            // 如果是0,保持隐藏,等待 busuanzi 更新
            element.style.display = 'none';
        }
    }

    // 使用轮询方式检查并格式化,避免阻塞页面
    function initBusuanziFormatter() {
        var checkCount = 0;
        var maxChecks = 50; // 最多检查50次(5秒)
        
        var checkInterval = setInterval(function() {
            // 格式化站点统计
            formatElement('busuanzi_value_site_pv');
            formatElement('busuanzi_value_site_uv');
            
            // 格式化文章访问量(只在单页显示,列表页通过 CSS 隐藏)
            var pagePv = document.getElementById('busuanzi_value_page_pv');
            if (pagePv) {
                formatElement('busuanzi_value_page_pv');
                // 如果值不是0,显示容器
                var container = pagePv.closest('.article-views');
                if (container && pagePv.textContent.trim() !== '0') {
                    container.style.display = '';
                }
            }
            
            checkCount++;
            if (checkCount >= maxChecks) {
                clearInterval(checkInterval);
            }
        }, 100); // 每100ms检查一次
    }

    // 页面加载完成后初始化
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', initBusuanziFormatter);
    } else {
        initBusuanziFormatter();
    }
})();
</script>
{{- end -}}

2.3.5 隐藏列表页访问量

themes/hugo-theme-stack/assets/scss/partials/article.scss 中添加 CSS 规则,隐藏列表页中的访问量:

.article-list--compact {
    // ... 其他样式 ...
    
    .article-views {
        display: none !important;
    }
}

2.4 功能说明

2.4.1 站点统计

显示位置:页脚 showStats 之后

显示内容

  • 总访问量:站点所有页面的访问次数总和
  • 总访客数:访问站点的独立访客数

显示格式

  • 总访问量X次,总访客数X人
  • 数字大于 1000 时自动转换为 k 格式

2.4.2 文章访问量

显示位置:文章详情页的 article-time footer 中

显示内容

  • 当前文章的阅读次数

显示格式

  • X 次阅读
  • 数字大于 1000 时自动转换为 k 格式
  • 初始值 0 时隐藏,数据加载后显示

注意事项

  • 列表页中不显示访问量(通过 CSS 隐藏)
  • 只在文章详情页显示

2.4.3 数字格式化

格式化规则

  • 小于 1000:显示原数字(如 999)
  • 大于等于 1000:转换为 k 格式(如 1500 → 1.5k,10000 → 10.0k)

防止重复格式化

  • 使用 data-formatted 属性标记已格式化的元素
  • 检查值是否已包含 ‘k’,避免重复格式化

2.5 显示位置

统计信息显示顺序:

  1. customText(自定义文本)
  2. showRuntime(运行时间统计)
  3. showStats(文章统计)
  4. busuanzi 站点统计(总访问量、总访客数)
  5. 主题信息

2.6 使用示例

启用所有 busuanzi 功能

params:
    busuanzi:
        enabled: true
        article:
            enabled: true
        footer:
            enabled: true

只启用站点统计

params:
    busuanzi:
        enabled: true
        article:
            enabled: false
        footer:
            enabled: true

只启用文章访问量

params:
    busuanzi:
        enabled: true
        article:
            enabled: true
        footer:
            enabled: false

2.7 注意事项

  1. 数据存储

    • busuanzi 数据存储在第三方服务器(busuanzi.ibruce.info)
    • 无法手动修改访问数据
    • 如需完全控制数据,建议使用自建统计服务(如 Umami)
  2. 性能优化

    • 使用 async 异步加载脚本,不阻塞页面渲染
    • 格式化脚本放在页面底部执行
    • 使用轮询方式检查数据更新,避免无限循环
  3. 显示优化

    • 初始值 0 时隐藏,避免闪烁
    • 列表页通过 CSS 强制隐藏访问量
    • 防止重复格式化,避免显示异常值(如 33360.3k)
  4. 兼容性

    • busuanzi 服务依赖第三方,可能出现不稳定情况
    • 建议定期检查统计是否正常
    • 如遇异常数据,可联系 busuanzi 作者或考虑切换统计服务

文件修改清单

修改的文件

  1. themes/hugo-theme-stack/hugo.yaml

    • params.footer 中添加 showStatsshowRuntime 配置开关
    • 添加 params.busuanzi 配置
  2. themes/hugo-theme-stack/layouts/partials/footer/footer.html

    • 添加 showRuntime 运行时间统计功能
    • 添加 showStats 文章统计功能
    • 添加 busuanzi 站点统计显示
  3. themes/hugo-theme-stack/layouts/partials/article/components/details.html

    • 添加 busuanzi 文章访问量显示
  4. layouts/partials/google_analytics.html(新建)

    • 加载 busuanzi 脚本
  5. themes/hugo-theme-stack/layouts/partials/footer/components/script.html

    • 添加 busuanzi 数字格式化脚本
  6. themes/hugo-theme-stack/assets/scss/partials/article.scss

    • 添加 CSS 规则,隐藏列表页中的访问量

测试验证

页脚统计功能

  • showStats 开关正确控制文章统计显示
  • showRuntime 开关正确控制运行时间统计显示
  • 文章统计显示正确的文章数和字数(万、千格式)
  • 运行时间统计从第一篇文章日期开始计算
  • 运行时间格式正确(x 年 x 月 x 天)
  • 没有文章时不显示运行时间统计

busuanzi 访问量统计

  • 站点统计正确显示总访问量和总访客数
  • 文章详情页正确显示文章阅读量
  • 列表页不显示访问量
  • 数字大于 1000 时正确转换为 k 格式
  • 初始值 0 时隐藏,数据加载后显示
  • 不会出现重复格式化问题

总结

通过以上集成,实现了:

  1. 页脚统计功能:显示文章统计和运行时间,增强网站信息展示
  2. busuanzi 访问量统计:集成第三方统计服务,显示站点和文章的访问数据
  3. 数字格式化:自动将大数字转换为易读的 k 格式
  4. 显示优化:避免闪烁和重复格式化问题,提升用户体验

这些功能都遵循了主题的设计规范,使用主题提供的 CSS 变量和响应式断点,确保样式的一致性和可维护性。

陕ICP备20000710号
本站已运行15年4月22天
发表了391篇文章 · 总计13万8千字
Built with Hugo
Theme Stack designed by Jimmy