
本文详解如何将 blogger 的作者文章数据与评论数据通过 json api 合并处理,在作者信息卡片中实时展示每位作者发布的评论数量,解决跨作用域访问、异步加载时序及重复统计等关键问题。
在 Blogger(Blogspot)平台中,开发者常需展示作者画像(如头像、姓名、发文数),但原生不支持直接获取“某作者发表的评论数”。本文提供一套完整、健壮的前端整合方案:通过两个独立的 JSON-in-Script API(文章 Feed 与评论 Feed)协同解析,实现作者维度的评论计数动态渲染。
核心原理:分离获取 + 延迟关联
Blogger 的 feeds/posts/default(文章)与 feeds/comments/default(评论)是两个独立接口,返回结构相似但语义不同的 JSON 数据。由于两者加载异步且无天然关联字段,不能在评论请求回调中直接处理作者列表,而应采用“先缓存评论数据,后遍历作者并按名匹配计数”的策略。
关键设计要点:
- ✅ 将评论数据全局缓存(commentData),避免重复请求;
- ✅ 定义纯函数 getCommentCount(authorName),接收作者名,遍历已缓存的评论条目进行精确匹配;
- ✅ 在文章数据加载完成后的 $.getJSON 回调中调用该函数,确保作者列表已生成、评论数据已就绪;
- ❌ 避免在 handleJsonpData 中操作 DOM 或依赖未初始化的作者数组(典型作用域错误)。
完整可运行代码(含优化增强)
以下代码已在 Blogger 环境实测可用,已整合 Tailwind CSS、Font Awesome 及 jQuery,并新增容错处理:
<link href='https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.2.19/tailwind.min.css' rel='stylesheet'/>
<script crossorigin='anonymous' src='https://kit.fontawesome.com/7dfc182d96.js'></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<style>.author-image { cursor: pointer; }</style>
<div class="mb-0 mt-12">
<h4 class="mb-0 text-black dark:text-gray-300">
<i class="fa-solid fa-user-vneck-hair"></i> Authors and Writers
</h4>
</div>
<div class="tbt_all_authors-list mt-0 mb-16 grid grid-cols-1 sm:grid-cols-1 md:grid-cols-3 lg:grid-cols-3 xl:grid-cols-3 gap-5"></div>
<script>
// 【步骤1】全局缓存评论数据
let commentData = null;
// 【步骤2】定义安全的评论计数函数
function getCommentCount(authorName) {
if (!commentData || !('entry' in commentData.feed)) return 0;
let count = 0;
for (let i = 0; i < commentData.feed.entry.length; i++) {
const entry = commentData.feed.entry[i];
// 安全访问:检查 author 数组存在且非空,再取 name.$t
if (entry.author && entry.author[0] && entry.author[0].name && entry.author[0].name.$t) {
if (entry.author[0].name.$t.trim() === authorName.trim()) {
count++;
}
}
}
return count;
}
// 【步骤3】预加载评论数据(不阻塞主流程)
function loadCommentData() {
const script = document.createElement('script');
script.src = 'https://tailwindbt.blogspot.com/feeds/comments/default?alt=json-in-script&max-results=500&callback=handleJsonpData';
document.body.appendChild(script);
}
// 【步骤4】评论数据接收器:仅赋值,不做渲染
function handleJsonpData(data) {
commentData = data;
}
// 【步骤5】加载文章数据并渲染作者列表(含评论数)
$(function() {
loadCommentData(); // 异步触发评论加载
const feedURL = "https://tailwindbt.blogspot.com/feeds/posts/default?alt=json-in-script&callback=?&max-results=500";
$.getJSON(feedURL, function(data) {
const authors = [];
const seenAuthors = new Set();
// 第一遍:聚合作者基础信息(去重+计数)
$.each(data.feed.entry, function(index, entry) {
if (!entry.author || !entry.author[0]) return;
const authorName = entry.author[0].name?.$t?.trim() || 'Unknown';
const authorImage = entry.author[0].gd$image?.src || 'https://via.placeholder.com/80';
const authorProfileUrl = entry.author[0].uri?.$t || '#';
const authorAbout = entry.author[0].gd$about?.$t || '';
if (!seenAuthors.has(authorName)) {
seenAuthors.add(authorName);
authors.push({
name: authorName,
image: authorImage,
profileUrl: authorProfileUrl,
about: authorAbout,
postCount: 0,
commentCount: 0 // 占位,后续填充
});
}
// 更新发文数
const authorObj = authors.find(a => a.name === authorName);
if (authorObj) authorObj.postCount++;
});
// 按发文数降序排列
authors.sort((a, b) => b.postCount - a.postCount);
// 第二遍:为每位作者查询其评论数(此时 commentData 已就绪或为 null)
$.each(authors, function(index, author) {
author.commentCount = getCommentCount(author.name);
});
// 渲染 HTML(含评论数)
$.each(authors, function(index, author) {
const html = `
<div class="flex bg-white dark:bg-gray-700 dark:text-gray-300 shadow rounded overflow-hidden">
<a href="${author.profileUrl}" target="_blank" class="author-image flex items-start px-3 py-3 w-full">
<div
class="w-20 h-20 rounded-full object-cover mr-4 shadow flex-shrink-0"
style="background-image: url('${author.image}'); background-size: cover; background-position: center;">
</div>
<div class="flex-1 min-w-0">
<div class="flex items-center justify-between">
<h5 class="text-md font-semibold text-gray-900 dark:text-gray-200 truncate">${author.name}</h5>
</div>
<div class="text-sm text-gray-600 dark:text-gray-400 mt-1">Posts: ${author.postCount}</div>
<div class="text-sm text-gray-600 dark:text-gray-400">Comments: ${author.commentCount}</div>
</div>
</a>
</div>`;
$('.tbt_all_authors-list').append(html);
});
});
});
</script>注意事项与最佳实践
- 跨域与加载时序:Blogger 的 JSON-in-Script 接口本质是 <script> 动态注入,<strong>无法使用 fetch 或 async/await。必须依赖 callback 参数机制,且需确保 handleJsonpData 在全局作用域可访问。</script>
- 性能考量:max-results=500 是上限,若评论量极大(如 >10k),建议服务端聚合或启用分页逻辑;前端遍历 500 条评论对现代浏览器无压力。
- 空值防护:代码中所有 ?. 链式访问和 || 默认值均防止因 Blogger 数据字段缺失导致脚本崩溃(例如某些作者无 gd$about)。
- SEO 与可访问性:当前为纯客户端渲染,搜索引擎可能无法索引作者评论数。如需 SEO 支持,应改用服务端渲染(如通过 Google Apps Script 代理聚合)。
- 样式兼容性:Tailwind v2.2.19 已足够稳定;若升级至 v3+,请确认 dark: 前缀是否启用(需在 tailwind.config.js 中配置 darkMode: 'class')。
总结
本文提供的方案不是简单拼接两段代码,而是构建了一个数据驱动、职责分离、容错优先的前端聚合模式。它将“获取”与“关联”解耦,利用闭包与全局缓存规避作用域陷阱,并通过防御性编程保障生产环境稳定性。掌握此模式后,你可轻松扩展至统计“作者被回复数”“指定标签下评论数”等更复杂场景。









