1.代码的核心作用
这段代码的主要任务是为你的每一篇文章自动生成"页脚组件”,包含两个功能:
·发布日期:从系统数据中提取精准的发布时间。
·智能翻页:自动计算"上一篇"和"下一篇”的链接,方便你在手表上连续阅读,不用跳回首页。
2.数据是从哪里拿的?
代码并不是凭空产生数据的,它像一个"小爬虫”,在后台做了一次极速访问:
·目标文件:它会读取你博客根目录下的 /rss.xml文件。
rss.xml是Gmeek 必生成的标准文件。它里面按时间顺序排列了你所有的文章标题、链接和日期。
·匹配逻辑:代码获取 RSS 列表后,会将当前页面的网址(URL)与列表里的链接逐一比对。一旦对上了,它就知道"我是谁”,同时也知道了排在我前面和后面的是哪两篇文章。
3.性能表现:
我设计了*“哨兵机制"**:
·轮询监听:由于 Gmeek 的内容 (postBody) 是动态渲染的,代码设置了一个300ms 的“哨兵”。它每隔0.3秒看一眼页面:“文章加载完了吗?”
·即刻下班:一旦哨兵发现文章内容出现了,它会立即执行clearInterval。这就像哨兵接到了人就立刻撤岗,后续不再消耗任何CPU资源。
4.它是如何插入到页面的?
代码采用了**”智能定位插入”**:
·它首先寻找文章的主体区域 postBodyo
·特殊处理:如果你在文章末尾加了“转载请注明出处"之类的提示,代码会智能识别这些文字,并把日期和翻页放在这些提示的下面,确保排版符合直觉。
注意事项:
代码内部的路径修改
在 js 中,有一行代码是核心数据来源:
xhr.open('GET','/rss.xml',true);
·注意事项:开头的/代表网站的根目录。
·如何修改:如果你的博客就在二级域名的根目录下(例如访问 g.weich.ee 直接就是首页),那么这行代码不需要动,它会自动去 g.weich.ee/rss.xml 拿数据。
·特殊情况:如果你是放在二级域名的子目录下(如
g.weich.ee/blog/ ),你必须把路径改成 xhr.open('GET', '/blog/rss.xml', true); 。
(function() {
if (window.GmeekFooterDone) return;
function initGmeekPlugins() {
var postBody = document.getElementById('postBody');
if (!postBody) return;
clearInterval(footerInterval);
window.GmeekFooterDone = true;
var xhr = new XMLHttpRequest();
xhr.open('GET', '/rss.xml', true);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
try {
var xml = xhr.responseXML || new DOMParser().parseFromString(xhr.responseText, "text/xml");
var items = xml.getElementsByTagName("item");
var posts = [];
var curPath = window.location.pathname;
var currentIndex = -1;
// 1. 快速提取并定位当前文章
for (var i = 0; i < items.length; i++) {
var link = items[i].getElementsByTagName("link")[0].textContent;
var title = items[i].getElementsByTagName("title")[0].textContent;
var date = items[i].getElementsByTagName("pubDate")[0].textContent;
posts.push({title: title, link: link, date: date});
if (currentIndex === -1 && (link.indexOf(curPath) !== -1 || curPath.indexOf(link) !== -1)) {
currentIndex = i;
}
}
if (currentIndex === -1) return;
// 2. 格式化日期
var d = new Date(posts[currentIndex].date);
var dateStr = d.getFullYear() + '-' + (d.getMonth() + 1) + '-' + d.getDate();
// 3. 构建极简 UI
var footerDiv = document.createElement('div');
footerDiv.style.cssText = "margin-top:30px; padding-top:20px; border-top:1px solid var(--color-border-default); clear:both; font-size:14px;";
var html = '<div style="color:var(--color-fg-muted); margin-bottom:15px;">📅 发布日期:' + dateStr + '</div>';
html += '<div style="display:flex; flex-direction:column; gap:10px;">';
if (currentIndex > 0) {
html += '<a href="' + posts[currentIndex - 1].link + '" style="color:var(--color-accent-fg); text-decoration:none;">← 下一篇:' + posts[currentIndex - 1].title + '</a>';
}
if (currentIndex < posts.length - 1) {
html += '<a href="' + posts[currentIndex + 1].link + '" style="color:var(--color-accent-fg); text-decoration:none;">→ 上一篇:' + posts[currentIndex + 1].title + '</a>';
}
html += '</div>';
footerDiv.innerHTML = html;
// 4. 精准插入位置
var target = postBody.nextElementSibling;
if (target && target.innerText && target.innerText.indexOf('转载') !== -1) {
target.parentNode.insertBefore(footerDiv, target.nextSibling);
} else {
postBody.parentNode.insertBefore(footerDiv, postBody.nextSibling);
}
} catch (e) { console.error("Footer Mini Error:", e); }
}
};
xhr.send();
}
var footerInterval = setInterval(initGmeekPlugins, 300);
})();
更新细节版本
这个修改的核心逻辑是将原本包裹在 标签内的"-下一篇"和"←上一篇"文本提取出来,放在 标签中,这样它们就不会被视为链接的一部分,且不会有点击效果。
修改说明:
1.结构拆解:原代码中←上一篇:是放在 标签里的。现在我为每一行加了一个
2.视觉统一:给 加了
color:var(--color-fg-muted);,使其颜色与发布日期的灰色保持一致,这样只有文章标题是蓝色的链接色,整体更清爽。
3.独立性:现在鼠标悬停在”下一篇”上时不会出现下划线,也不会触发链接,只有点击标题才会跳转。
本次变动:
1.文字与链接解耦:←上一篇:和→下一篇:现在包裹在 中,不会变色,也不会响应点击。2. 顺序对调:
·currentIndex -1(数组中靠前的,即最新的)现在对应ー上一篇。
·currentIndex +1(数组中靠后的,即旧的)现在对应一下一篇。
这样就符合“新文章在旧文章上方”的逻辑顺序了。
这个问题以前我在用 Typecho程序 的时候跟别人争议过,就差点没干起来了,我现在才想起来所以更新一下变动,我的想法是第二种就是现在这种更新之后的方式。
(function() {
if (window.GmeekFooterDone) return;
function initGmeekPlugins() {
var postBody = document.getElementById('postBody');
if (!postBody) return;
clearInterval(footerInterval);
window.GmeekFooterDone = true;
var xhr = new XMLHttpRequest();
xhr.open('GET', '/rss.xml', true);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
try {
var xml = xhr.responseXML || new DOMParser().parseFromString(xhr.responseText, "text/xml");
var items = xml.getElementsByTagName("item");
var posts = [];
var curPath = window.location.pathname;
var currentIndex = -1;
for (var i = 0; i < items.length; i++) {
var link = items[i].getElementsByTagName("link")[0].textContent;
var title = items[i].getElementsByTagName("title")[0].textContent;
var date = items[i].getElementsByTagName("pubDate")[0].textContent;
posts.push({title: title, link: link, date: date});
if (currentIndex === -1 && (link.indexOf(curPath) !== -1 || curPath.indexOf(link) !== -1)) {
currentIndex = i;
}
}
if (currentIndex === -1) return;
var d = new Date(posts[currentIndex].date);
var dateStr = d.getFullYear() + '-' + (d.getMonth() + 1) + '-' + d.getDate();
var footerDiv = document.createElement('div');
footerDiv.style.cssText = "margin-top:30px; padding-top:20px; border-top:1px solid var(--color-border-default); clear:both; font-size:14px;";
var html = '<div style="color:var(--color-fg-muted); margin-bottom:15px;">📅 发布日期:' + dateStr + '</div>';
html += '<div style="display:flex; flex-direction:column; gap:10px;">';
// 索引较小 (currentIndex - 1) 的是更新的文章,即“上一篇”
if (currentIndex > 0) {
html += '<div><span style="color:var(--color-fg-muted);">← 上一篇:</span><a href="' + posts[currentIndex - 1].link + '" style="color:var(--color-accent-fg); text-decoration:none;">' + posts[currentIndex - 1].title + '</a></div>';
}
// 索引较大 (currentIndex + 1) 的是更旧的文章,即“下一篇”
if (currentIndex < posts.length - 1) {
html += '<div><span style="color:var(--color-fg-muted);">→ 下一篇:</span><a href="' + posts[currentIndex + 1].link + '" style="color:var(--color-accent-fg); text-decoration:none;">' + posts[currentIndex + 1].title + '</a></div>';
}
html += '</div>';
footerDiv.innerHTML = html;
var target = postBody.nextElementSibling;
if (target && target.innerText && target.innerText.indexOf('转载') !== -1) {
target.parentNode.insertBefore(footerDiv, target.nextSibling);
} else {
postBody.parentNode.insertBefore(footerDiv, postBody.nextSibling);
}
} catch (e) { console.error("Footer Mini Error:", e); }
}
};
xhr.send();
}
var footerInterval = setInterval(initGmeekPlugins, 300);
})();
结论:
建议全局引用(放在 config.json 的 healer 中,不是直接把代码放进去config.json,也可以通过外部js文件然后在 healer 引用的意思)虽然这段代码的最终效果只在文章页面显示,但将其作为全局引用是目前最稳妥、也是 Gmeek 框架默认推荐的做法。原因如下:
代码已经自带”智能识别"功能
在代码的开头,有一行关键的逻辑判断,这个不用另外加进去,上面已经有了:
var postBody = document.getElementById('postBody');
if (!postBody) return;
·它的作用:当你在首页、标签页(tag.html)或关于页时,脚本虽然会加载,但它发现页面上没有 postBody(正文容器),就会立即停止运行(return)。
·性能影响:这种判断在毫秒级就能完成,对非文章页面的性能消耗微乎其微。
更新加在文章内显示标签
是直接替换原来的全部代码。
(function() {
let checkCount = 0;
const run = () => {
const c = document.getElementById('cmButton');
// 等待评论按钮出现,最多尝试 10 秒
if (!c) {
if (checkCount++ < 20) setTimeout(run, 500);
return;
}
if (document.getElementById('customLabels')) return;
const p = window.location.pathname;
const u = window.location.href;
// 1. 抓取 RSS:日期与上下篇
fetch("/rss.xml").then(r => r.text()).then(x => {
const d = new DOMParser().parseFromString(x, "text/xml");
const items = Array.from(d.querySelectorAll("item"));
let idx = -1;
// 采用最稳的双向匹配逻辑
for (let i = 0; i < items.length; i++) {
const link = items[i].querySelector("link").textContent;
if (link.indexOf(p) !== -1 || p.indexOf(link) !== -1 || link === u) {
idx = i;
break;
}
}
if (idx === -1) return;
const pub = new Date(items[idx].querySelector("pubDate").textContent);
const dt = pub.getFullYear() + '-' + (pub.getMonth() + 1) + '-' + pub.getDate();
const box = document.createElement('div');
// 设置整体容器样式
box.style.cssText = "margin-top:30px;padding-top:20px;border-top:1px solid var(--color-border-default);clear:both;font-size:14px;";
let h = '<div style="color:var(--color-fg-muted);margin-bottom:15px;">📅 发布日期:' + dt + '</div><div style="display:flex;flex-direction:column;gap:10px;">';
// 索引越小越新,索引越大越旧
if (idx > 0) {
h += '<div><span style="color:var(--color-fg-muted);">← 上一篇:</span><a href="' + items[idx - 1].querySelector("link").textContent + '" style="color:var(--color-accent-fg);text-decoration:none;">' + items[idx - 1].querySelector("title").textContent + '</a></div>';
}
if (idx < items.length - 1) {
h += '<div><span style="color:var(--color-fg-muted);">→ 下一篇:</span><a href="' + items[idx + 1].querySelector("link").textContent + '" style="color:var(--color-accent-fg);text-decoration:none;">' + items[idx + 1].querySelector("title").textContent + '</a></div>';
}
h += '</div>';
box.innerHTML = h;
c.before(box);
// 2. 抓取标签:使用严格后缀匹配,修正个位数 ID 错误
const s = (url) => {
fetch(url).then(r => r.text()).then(ht => {
const doc = new DOMParser().parseFromString(ht, "text/html");
const pathName = p.split('/').pop();
// 核心修复:使用 [href$='/3.html'] 这种结尾匹配,防止误抓 33.html
const exactSelector = "a[href$='/" + pathName + "']";
const postEntry = doc.querySelector(exactSelector);
const container = postEntry ? postEntry.closest('.SideNav-item') : null;
if (container) {
const b = document.createElement('div');
b.id = "customLabels";
// 修正:增加 margin-top: 15px 让标签和上面的链接分开
b.style.cssText = "margin-top:15px;margin-bottom:15px;display:flex;flex-wrap:wrap;gap:8px;";
container.querySelectorAll("span[class*='Label']").forEach(l => {
const t = l.innerText.trim();
if (t && !/^\d{4}/.test(t)) {
const a = document.createElement('a');
a.href = "/tag.html#" + t;
a.innerText = t;
// 克隆样式获取颜色
const temp = document.body.appendChild(l.cloneNode(true));
temp.style.display = "none";
const bg = window.getComputedStyle(temp).backgroundColor;
document.body.removeChild(temp);
a.style.cssText = "background-color:" + bg + ";color:#fff;padding:2px 10px;border-radius:20px;font-size:12px;text-decoration:none;display:inline-block;";
b.appendChild(a);
}
});
if (b.children.length > 0) c.before(b);
} else {
// 没找到就翻下一页
const n = doc.querySelector('.pagination a:last-child, a[rel="next"]');
if (n && n.getAttribute('href') && n.getAttribute('href') !== url) s(n.getAttribute('href'));
}
});
};
s("/index.html");
});
};
run();
})();
说明和注意事项
🛠️ 技术实现原理
1. 数据从哪来?
日期与上下篇:从 /rss.xml 获取。RSS 是 Gmeek 自动生成的,里面包含了所有文章的标题、链接和发布日期。
彩色标签:从 /index.html(或翻页后的首页)获取。脚本会模拟访问首页,找到对应的文章条目,并克隆其标签样式。
2. 是如何做的?
异步抓取 (Fetch):脚本在后台悄悄访问 RSS 和首页,不会刷新页面或影响用户阅读。
严格后缀匹配:使用 a[href$='/ID.html']。$ 符号代表“以...结尾”,确保 100% 匹配到正确的文章 ID。
隐身样式提取:将首页标签克隆到内存中,用 getComputedStyle 偷取它的背景色,然后再应用到文章页的标签上。
文件名规范:
尽量不要修改 Gmeek 默认的 post/ID.html 命名规则。如果你手动改了文件名,脚本可能需要根据新的路径规则调整匹配逻辑。
首页标签显示数量:
脚本是去首页“找”标签。如果你在 Gmeek 设置里让首页完全不显示标签,那么文章页也就抓不到颜色了。
性能开销:
无需担心。目前的脚本带有 checkCount < 20 的自毁机制。如果在 10 秒内没找到位置,它会自动停止运行,不会持续消耗设备的 CPU 或电池。
间距调整:
如果以后觉得标签和上面的链接还是太近或太远,搜索代码中的 margin-top:15px;。调大数字(如 25px)间距就会变大。
如果发现某些新标签颜色没变怎么办?
修改点:在自适应字体脚本中,找到 const l = '...' 这一行,在后面添加该标签的 CSS 类名(用逗号隔开)。
更新添加本文标签文本
(function() {
let checkCount = 0;
const run = () => {
const c = document.getElementById('cmButton');
// 等待评论按钮出现,最多尝试 10 秒
if (!c) {
if (checkCount++ < 20) setTimeout(run, 500);
return;
}
if (document.getElementById('customLabels')) return;
const p = window.location.pathname;
const u = window.location.href;
// 1. 抓取 RSS:日期与上下篇
fetch("/rss.xml").then(r => r.text()).then(x => {
const d = new DOMParser().parseFromString(x, "text/xml");
const items = Array.from(d.querySelectorAll("item"));
let idx = -1;
// 采用最稳的双向匹配逻辑
for (let i = 0; i < items.length; i++) {
const link = items[i].querySelector("link").textContent;
if (link.indexOf(p) !== -1 || p.indexOf(link) !== -1 || link === u) {
idx = i;
break;
}
}
if (idx === -1) return;
const pub = new Date(items[idx].querySelector("pubDate").textContent);
const dt = pub.getFullYear() + '-' + (pub.getMonth() + 1) + '-' + pub.getDate();
const box = document.createElement('div');
// 设置整体容器样式
box.style.cssText = "margin-top:30px;padding-top:20px;border-top:1px solid var(--color-border-default);clear:both;font-size:14px;";
let h = '<div style="color:var(--color-fg-muted);margin-bottom:15px;">📅 发布日期:' + dt + '</div><div style="display:flex;flex-direction:column;gap:10px;">';
// 索引越小越新,索引越大越旧
if (idx > 0) {
h += '<div><span style="color:var(--color-fg-muted);">← 上一篇:</span><a href="' + items[idx - 1].querySelector("link").textContent + '" style="color:var(--color-accent-fg);text-decoration:none;">' + items[idx - 1].querySelector("title").textContent + '</a></div>';
}
if (idx < items.length - 1) {
h += '<div><span style="color:var(--color-fg-muted);">→ 下一篇:</span><a href="' + items[idx + 1].querySelector("link").textContent + '" style="color:var(--color-accent-fg);text-decoration:none;">' + items[idx + 1].querySelector("title").textContent + '</a></div>';
}
h += '</div>';
box.innerHTML = h;
c.before(box);
// 2. 抓取标签:使用严格后缀匹配,修正个位数 ID 错误
const s = (url) => {
fetch(url).then(r => r.text()).then(ht => {
const doc = new DOMParser().parseFromString(ht, "text/html");
const pathName = p.split('/').pop();
// 核心修复:使用 [href$='/3.html'] 这种结尾匹配,防止误抓 33.html
const exactSelector = "a[href$='/" + pathName + "']";
const postEntry = doc.querySelector(exactSelector);
const container = postEntry ? postEntry.closest('.SideNav-item') : null;
if (container) {
const b = document.createElement('div');
b.id = "customLabels";
// 修正:增加 margin-top: 15px 让标签和上面的链接分开
b.style.cssText = "margin-top:15px;margin-bottom:15px;display:flex;flex-wrap:wrap;gap:8px;align-items:center;";
// 添加提示文字
b.innerHTML = '<span style="color:var(--color-fg-muted);font-size:14px;">本文标签:</span>';
container.querySelectorAll("span[class*='Label']").forEach(l => {
const t = l.innerText.trim();
// 校验标签内容:排除以4位数字(年份)开头的日期标签
if (t && !/^\d{4}/.test(t)) {
const a = document.createElement('a');
a.href = "/tag.html#" + t;
a.innerText = t;
// 克隆样式获取颜色
const temp = document.body.appendChild(l.cloneNode(true));
temp.style.display = "none";
const bg = window.getComputedStyle(temp).backgroundColor;
document.body.removeChild(temp);
a.style.cssText = "background-color:" + bg + ";color:#fff;padding:2px 10px;border-radius:20px;font-size:12px;text-decoration:none;display:inline-block;";
b.appendChild(a);
}
});
if (b.children.length > 1) c.before(b);
} else {
// 没找到就翻下一页
const n = doc.querySelector('.pagination a:last-child, a[rel="next"]');
if (n && n.getAttribute('href') && n.getAttribute('href') !== url) s(n.getAttribute('href'));
}
});
};
s("/index.html");
});
};
run();
})();
修改点:
第 74 行:添加了注释 // 校验标签内容:排除以4位数字(年份)开头的日期标签。
第 70 行:加入了 b.innerHTML = ... 提示文字。
第 90 行:判断改为 > 1 以匹配包含提示文字后的容器。
第90行,判断改这个有什么作用?不改留着原版会怎样?
改动这一行是为了逻辑的严谨性,防止页面上出现一个“空标签栏”。
1. 为什么要改(> 1 的作用)?
在原版代码中,标签容器 b 刚创建时是全空的。
原版逻辑:if (b.children.length > 0) 意思是“只要里面抓到了标签,就把这块区域显示出来”。
但在新版中,我们在循环抓取标签之前,先执行了这一句:
b.innerHTML = '<span ...>本文标签:';
这导致容器 b 一出生就自带了 1 个 子元素(即“本文标签:”这五个字)。
新版逻辑 (> 1):意思是“除了‘本文标签:’这五个字外,必须至少抓到一个真正的标签,才把这块区域显示出来”。
2. 如果不改(留着原版 > 0)会怎样?
如果你留着 > 0,会产生一个视觉 Bug:
现象:如果某篇文章没有任何标签(比如你在 GitHub Issue 里没打标签),脚本依然会检测到 b.children.length 等于 1(因为有那句提示文字)。
结果:文章底部会莫名其妙出现一行孤零零的 “本文标签:”,后面什么都没有,看起来像代码出错了。
总结
> 1:确保只有在“有提示语”+“有实际标签”的情况下才显示。
> 0:会导致没有标签的文章也显示一个尴尬的提示语。
所以,为了让我们的博客看起来更专业,建议保留 > 1 这个改动,我的原则能不加就不加,能做减法就不做加法,但是我还是加好一点,还有个问题就是Gmeek不可能文章没有标签,因为没有标签文章也不会显示,我还是加了,为什么,因为还有另外一个BUG修起来更大,就是在友情链接(网址)页面也会显示,就是除了这个页面没有"文章标签"之外其它的都有,为了预防不在友情链接这个页面显示一个(本文标签)而后面什么标签都没有,所以添加了这个判断,说多感觉字又打多了,总之自己看着办…
想要干净的,其实这个(本文标签)这个文本都不用添加…
大更新变换判断方式加排除评论数量
这段代码使用了 span.LabelName 精确匹配,彻底解决评论数被抓取的问题。
代码改进说明:
标签过滤:将 querySelectorAll("span[class*='Label']") 换成了更精准的 querySelectorAll("span.LabelName")。这会直接忽略掉 class 为 Label(评论数)和 LabelTime(日期)的元素。
结构保留:保留了“发布日期”和“上下篇链接”逻辑。
样式优化:标签依然会自动获取首页定义的标签背景颜色,并保持胶囊形状。
也是完整代码全部覆盖替换。
(function() {
let checkCount = 0;
const run = () => {
const c = document.getElementById('cmButton');
// 等待评论按钮出现,最多尝试 10 秒
if (!c) {
if (checkCount++ < 20) setTimeout(run, 500);
return;
}
// 防止重复加载
if (document.getElementById('customLabels')) return;
const p = window.location.pathname;
const u = window.location.href;
// 1. 抓取 RSS:处理日期与上下篇链接
fetch("/rss.xml").then(r => r.text()).then(x => {
const d = new DOMParser().parseFromString(x, "text/xml");
const items = Array.from(d.querySelectorAll("item"));
let idx = -1;
// 匹配当前文章在 RSS 中的索引
for (let i = 0; i < items.length; i++) {
const link = items[i].querySelector("link").textContent;
if (link.indexOf(p) !== -1 || p.indexOf(link) !== -1 || link === u) {
idx = i;
break;
}
}
if (idx === -1) return;
// 格式化发布日期
const pub = new Date(items[idx].querySelector("pubDate").textContent);
const dt = pub.getFullYear() + '-' + (pub.getMonth() + 1) + '-' + pub.getDate();
const box = document.createElement('div');
box.style.cssText = "margin-top:30px;padding-top:20px;border-top:1px solid var(--color-border-default);clear:both;font-size:14px;";
let h = '<div style="color:var(--color-fg-muted);margin-bottom:15px;">📅 发布日期:' + dt + '</div><div style="display:flex;flex-direction:column;gap:10px;">';
// 上一篇 (索引越小越新)
if (idx > 0) {
h += '<div><span style="color:var(--color-fg-muted);">← 上一篇:</span><a href="' + items[idx - 1].querySelector("link").textContent + '" style="color:var(--color-accent-fg);text-decoration:none;">' + items[idx - 1].querySelector("title").textContent + '</a></div>';
}
// 下一篇
if (idx < items.length - 1) {
h += '<div><span style="color:var(--color-fg-muted);">→ 下一篇:</span><a href="' + items[idx + 1].querySelector("link").textContent + '" style="color:var(--color-accent-fg);text-decoration:none;">' + items[idx + 1].querySelector("title").textContent + '</a></div>';
}
h += '</div>';
box.innerHTML = h;
c.before(box);
// 2. 抓取标签:通过首页列表获取
const s = (url) => {
fetch(url).then(r => r.text()).then(ht => {
const doc = new DOMParser().parseFromString(ht, "text/html");
const pathName = p.split('/').pop();
// 匹配首页中对应文章的链接
const exactSelector = "a[href$='/" + pathName + "']";
const postEntry = doc.querySelector(exactSelector);
const container = postEntry ? postEntry.closest('.SideNav-item') : null;
if (container) {
const b = document.createElement('div');
b.id = "customLabels";
b.style.cssText = "margin-top:15px;margin-bottom:15px;display:flex;flex-wrap:wrap;gap:8px;align-items:center;";
b.innerHTML = '<span style="color:var(--color-fg-muted);font-size:14px;">本文标签:</span>';
// 核心改进:只选择 class 为 LabelName 的 span,排除单纯的 Label(评论数) 和 LabelTime(日期)
container.querySelectorAll("span.LabelName").forEach(l => {
const t = l.innerText.trim();
if (t) {
const a = document.createElement('a');
a.href = "/tag.html#" + t;
a.innerText = t;
// 获取首页标签的背景颜色
const temp = document.body.appendChild(l.cloneNode(true));
temp.style.display = "none";
const bg = window.getComputedStyle(temp).backgroundColor;
document.body.removeChild(temp);
a.style.cssText = "background-color:" + bg + ";color:#fff;padding:2px 10px;border-radius:20px;font-size:12px;text-decoration:none;display:inline-block;";
b.appendChild(a);
}
});
// 只有抓取到标签时才插入
if (b.children.length > 1) c.before(b);
} else {
// 没找到则继续翻页寻找
const n = doc.querySelector('.pagination a:last-child, a[rel="next"]');
if (n && n.getAttribute('href') && n.getAttribute('href') !== url) s(n.getAttribute('href'));
}
});
};
s("/index.html");
});
};
run();
})();
这次优化的核心提升点:
减少 DOM 遍历:querySelectorAll("span.LabelName") 在浏览器底层是经过高度优化的,比带属性选择器的 [class*='Label'] 快得多。
砍掉正则判断:之前要用正则去匹配日期、匹配纯数字,现在这些计算开销全部归零。
减少节点操作:不再需要克隆那些无用的“评论数”节点去计算样式,内存占用更低。
这就好比之前是去一堆人里通过“长得像”来找人,还得查身份证排查;现在是直接对着工牌(Class Name)领人,当然快准狠。