使用Artalk 的 Hexo 站点数据统计实现方案
volantis主题对于artalk评论系统适配较为完善,可实现开箱即用的文章评论与基础浏览量统计功能。但如需扩展更多统计维度,需手动配置实现。虽然主题自带了busuanzi和leancloud统计,但是busuanzi加载真的太太太慢了,而且统计的很抽象,leancloud感觉又有点复杂。折腾artalk的过程中发现也能做到很多统计,搞一搞试试。
一、前言
统计功能的实现依赖于artalk评论组件的部署,对于首页、归档页等未默认配置评论功能的页面,需先添加评论组件并隐藏显示(仅用于统计数据收集)。例如以首页页面为例:
击查看代码
volantis/layout/layout.ejs1 2 3 4 5 6 7 8 9 10 11 12
| <div id="safearea"> <div class="body-wrapper"> <%- body %> <%- partial('_plugins/pjax/pdata') %> </div> <%- partial('_partial/footer', null, {cache: !config.relative_link}) %> <a id="s-top" class="fa-solid fa-arrow-up fa-fw" href="/" onclick="return false;" title="top"></a> </div> + <%# 首页添加artalk评论用于统计浏览量 %> + <div style="display: none"> + <%- partial('/_plugins/comments/index') %> + </div>
|
此外,所需样式代码引入可以直接写在blog/source/_volantis/bodyEnd.ejs文件中,确保统计组件的正常渲染。。
二、统计全站浏览量
1、收集目标页面 URL字段
为确保统计覆盖全站有效页面,需收集以下几类页面的 URL 并统一处理:
- 首页、归档页:直接手动添加;
- 所有文章页面:通过 Hexo 接口批量获取并处理链接格式;
- 自定义页面:从主题配置文件中提取链接(导航栏处)。
点击查看代码
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
| <%
const allPostUrls = [];
allPostUrls.push("/"); allPostUrls.push("/archives/");
site.posts.each(function (post) { if (post.archive === undefined || post.archive === true) { let postUrl = url_for(post.link || post.path); postUrl = postUrl.replace(/\.html$/, ''); allPostUrls.push(postUrl); } });
const list_menu = theme.navbar.menu list_menu.forEach(item => { if (item.rows && Array.isArray(item.rows)) { item.rows.forEach(row => { if (row.url) { allPostUrls.push(row.url); } }); } }); %>
|
注意:若未使用 permalink 优化文章链接,需在 “获取所有文章的 url” 步骤中调整代码逻辑以适配实际链接格式
最终收集的 url格式示例如下:
1 2 3
| allPostUrls=[ '/','/archives/', '/post/xxx/', '/post/xxx/', '/post/xxx/', '/about/', '/friends/', '/comment/', ]
|
2、调用 API 获取并展示浏览量
①首先在需要展示数据的页面中添加承载样式:
1 2 3 4
| <div class="stat-item"> <div class="stat-number stat-visitor" data-count="">0</div> <div class="stat-label">总阅读量</div> </div>
|
②通过 artalk API 获取数据并渲染到页面:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <%# 获取网站总浏览量 %> const siteName = '<%- config.title %>'; const new_allPostUrls = <%- JSON.stringify(allPostUrls) %>; var apiUrl = "<%- theme.comments.artalk.server %>/api/v2/stats/page_pv?page_keys=" + new_allPostUrls.join(",") + "&site_name=" + siteName; fetch(apiUrl).then(response => { if (!response.ok) { throw new Error('Network response was not ok'); } return response.json(); }).then(({data}) => { const totalViews = Object.values(data).reduce((sum, views) => sum + views, 0); const visitorEl = document.querySelector('.stat-visitor'); <%# visitorEl.dataset.count = totalViews; %> visitorEl.innerHTML = totalViews; }).catch(error => { console.error('There was a problem with the fetch operation:', error); });
|
三、统计总评论数
总评论数的统计逻辑与浏览量类似,直接调用 Artalk 提供的站点评论数 API 即可实现。
① 添加承载样式:
1 2 3 4
| <div class="stat-item"> <div class="stat-number stat-comment" data-count="">0</div> <div class="stat-label">总评论</div> </div>
|
② 调用 API 获取并展示数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <%# 获取网站总评论数 %> const url = `<%- theme.comments.artalk.server %>/api/v2/stats/site_comment?site_name=${encodeURIComponent(siteName)}`; fetch(url) .then(response => { if (!response.ok) { throw new Error('Network response was not ok'); } return response.json(); }) .then(({data}) => { const commentEl = document.querySelector('.stat-comment'); <%# commentEl.dataset.count = JSON.stringify(data); %> commentEl.innerHTML = JSON.stringify(data); }) .catch(error => { console.error('There was a problem with the fetch operation:', error); });
|
浏览量与评论数统计完整代码
将上述逻辑整合后,完整代码可放置于blog/source/_volantis/bodyEnd.ejs文件中:
点击查看代码
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
| <%
const allPostUrls = [];
allPostUrls.push("/"); allPostUrls.push("/archives/");
site.posts.each(function (post) { if (post.archive === undefined || post.archive === true) { let postUrl = url_for(post.link || post.path); postUrl = postUrl.replace(/\.html$/, ''); allPostUrls.push(postUrl); } });
const list_menu = theme.navbar.menu list_menu.forEach(item => { if (item.rows && Array.isArray(item.rows)) { item.rows.forEach(row => { if (row.url) { allPostUrls.push(row.url); } }); } });
%> <script> <%# 获取网站总浏览量 %> const siteName = '<%- config.title %>'; const new_allPostUrls = <%- JSON.stringify(allPostUrls) %>; var apiUrl = "<%- theme.comments.artalk.server %>/api/v2/stats/page_pv?page_keys=" + new_allPostUrls.join(",") + "&site_name=" + siteName; fetch(apiUrl).then(response => { if (!response.ok) { throw new Error('Network response was not ok'); } return response.json(); }).then(({data}) => { const totalViews = Object.values(data).reduce((sum, views) => sum + views, 0); const visitorEl = document.querySelector('.stat-visitor'); <%# visitorEl.dataset.count = totalViews; %> visitorEl.innerHTML = totalViews;
}).catch(error => { console.error('There was a problem with the fetch operation:', error); });
<%# 获取网站总评论数 %> const url = `<%- theme.comments.artalk.server %>/api/v2/stats/site_comment?site_name=${encodeURIComponent(siteName)}`; fetch(url) .then(response => { if (!response.ok) { throw new Error('Network response was not ok'); } return response.json(); }) .then(({data}) => { const commentEl = document.querySelector('.stat-comment'); <%# commentEl.dataset.count = JSON.stringify(data); %> commentEl.innerHTML = JSON.stringify(data); }) .catch(error => { console.error('There was a problem with the fetch operation:', error); }); </script>
|
四、文章卡片统计数据展示
常规统计逻辑中,文章详情页的统计数据会在加载 Artalk 评论组件后自动获取(推测)。但首页文章卡片需单独配置,以实现列表页的数据展示。
①添加卡片统计样式
volantis主题的首页文章卡片代码渲染位置在volantis/layout/_partial/post.ejs文件中,在合适的位置添加浏览量与评论数的展示容器:
1 2
| <span class="card_artalk_visitors" data-page-key="<%- url_for(post.link || post.path).replace(/\.html$/, '') %>">-</span><span>次浏览</span> <span class="card_artalk_comment" data-page-key="<%- url_for(post.link || post.path).replace(/\.html$/, '') %>">-</span><span>条评论</span>
|
本站样式参考
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <%# 浏览量 %> <div class="card-meta-counter"> <svg class="iconfont" aria-hidden="true"> <use xlink:href="#icon-redu"></use> </svg> <span class="card_artalk_visitors" data-page-key="<%- url_for(post.link || post.path).replace(/\.html$/, '') %>">-</span> <span><%- theme.article.body.meta_library.counter.unit %></span> </div> <%# 评论数 %> <div class="card-meta-comment"> <svg class="iconfont" aria-hidden="true"> <use xlink:href="#icon-woyaoliuyan"></use> </svg> <span class="card_artalk_comment" data-page-key="<%- url_for(post.link || post.path).replace(/\.html$/, '') %>">-</span> <span><%- theme.article.body.meta_library.artalkcount.desc %></span> </div>
|
②创建统计组件加载逻辑
在volantis/layout/_partial/custom目录下创建custom_card.ejs文件,编写卡片统计数据的加载逻辑:
点击查看代码
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
| <script> function card_load_artalk() { volantis.css("<%- theme.comments.artalk.css %>"); volantis.js("<%- theme.comments.artalk.js %>") .then(() => { if (typeof Artalk === 'undefined') { console.error('Artalk.js loaded but Artalk is not defined'); return; } return card_post_artalk(); }) .catch(err => { console.error('Failed to load Artalk.js:', err); }); }
function card_post_artalk() { if (!window.Artalk) { console.error("Artalk未加载,请检查脚本引入"); return; } Artalk.loadCountWidget({ server: '<%- theme.comments.artalk.server %>', site: '<%- config.title %>', pvEl: '.card_artalk_visitors', countEl: '.card_artalk_comment', statPageKeyAttr: 'data-page-key', }); } card_load_artalk(); </script>
|
注意:样式容器中的类名(如card_artalk_visitors)需与加载逻辑中的pvEl/countEl属性值保持一致,否则会导致数据无法正常渲染
③引入卡片统计组件
在首页文章列表的渲染文件中引入上述统计组件,确保数据在页面加载时同步加载:
volantis/layout/_partial/archive.ejs1 2 3 4 5 6 7 8
| <% if (site.posts && site.posts.length > 0) { %> + <%- partial('_partial/custom/custom_card') %> <section class="post-list"> <%# page.prev 表示“上一页”,!page.prev 即当前是第一页 %> <% if (!page.prev) { %> <%# is_home() 是 Hexo 辅助函数,判断当前是否为首页 %> <% if (is_home()) { %> ...
|
本站首页文章卡片样式参考:
总结
通过 Artalk 评论系统的内置 API,可高效实现全站浏览量、总评论数及文章卡片统计等功能,且数据加载速度取决于服务器部署位置,整体体验优于其他统计工具。另外Artalk的文档有点一言难尽,对小白来说太不友好了
条评论