2024-07-26 14:22:52 +08:00
|
|
|
|
// 定义pjax 预设pjax
|
2026-01-31 19:24:22 +08:00
|
|
|
|
(function() {
|
|
|
|
|
|
if (typeof Pjax === 'undefined') {
|
|
|
|
|
|
console.error('Pjax library is not loaded.');
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var pjax = new Pjax({
|
|
|
|
|
|
// 这里填写页面中改变的部分(和 CSS 选择器用法一样)
|
|
|
|
|
|
selectors: ["title", "#pjax-container"],
|
2026-10-07 23:12:39 +08:00
|
|
|
|
// ★ cacheBust 保持 false:重复导航靠浏览器 HTTP 缓存秒出(实测 1ms)。
|
|
|
|
|
|
// 开 true 会给每次 PJAX 加时间戳绕开缓存 → 每次导航多付 ~200-380ms
|
|
|
|
|
|
// 网络往返(2026-10-07 实测,用户可感知的「点 nav 卡一下」)。
|
|
|
|
|
|
// 新鲜度由两层兜底:① 部署换样式表指纹后,下方 pjax:success 的版本
|
|
|
|
|
|
// 同步自动整页刷一次;② CDN 的 HTML 缓存 TTL 应调短(控制台配置)。
|
|
|
|
|
|
cacheBust: false,
|
2026-01-31 19:24:22 +08:00
|
|
|
|
elements: "a", // 拦截所有链接
|
|
|
|
|
|
switches: {
|
|
|
|
|
|
"#pjax-container": Pjax.switches.default
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 将 pjax 实例挂载到 window 以便调试或外部访问
|
|
|
|
|
|
window.pjax = pjax;
|
|
|
|
|
|
|
|
|
|
|
|
console.log("Pjax initialized:", pjax);
|
|
|
|
|
|
})();
|
|
|
|
|
|
|
2026-10-07 22:54:28 +08:00
|
|
|
|
// ── 静态资源版本同步(修复「部署后 PJAX 页面样式裸奔」)──
|
|
|
|
|
|
// ─────────────────────────────────────────────────────────────
|
|
|
|
|
|
// 根因:Pjax 只换 title 和 #pjax-container,<head> 里的指纹 CSS
|
|
|
|
|
|
// (style.min.<hash>.css)一旦因部署换了指纹,**旧会话**里所有后续
|
|
|
|
|
|
// PJAX 页面都跑在旧样式上 —— 新 HTML 的类(.ab-* 等)在旧 CSS 里
|
|
|
|
|
|
// 不存在 → 内容裸奔成纯文本(2026-10-07 关于页上线实锤)。
|
|
|
|
|
|
//
|
|
|
|
|
|
// 解法:pjax:success 时事件对象上带有本次请求(pjax 库把 options 的
|
|
|
|
|
|
// 键直接拷到 event 上,options.request = XMLHttpRequest),从
|
|
|
|
|
|
// responseText 解析出新页面的样式表指纹,与当前 document 比对;
|
|
|
|
|
|
// 不一致 → 整页 reload 一次拿全新资源(sessionStorage 保证每次会话
|
|
|
|
|
|
// 至多一次,防异常情况下的循环刷新)。
|
|
|
|
|
|
document.addEventListener("pjax:success", function (e) {
|
|
|
|
|
|
var request = e.request;
|
|
|
|
|
|
if (!request || typeof request.responseText !== "string" || !request.responseText) return;
|
|
|
|
|
|
|
|
|
|
|
|
var fetchedLinks, currentLinks, i, changed = false;
|
|
|
|
|
|
try {
|
|
|
|
|
|
var doc = new DOMParser().parseFromString(request.responseText, "text/html");
|
|
|
|
|
|
fetchedLinks = doc.querySelectorAll('link[rel="stylesheet"]');
|
|
|
|
|
|
currentLinks = document.querySelectorAll('link[rel="stylesheet"]');
|
|
|
|
|
|
} catch (err) { return; }
|
|
|
|
|
|
|
|
|
|
|
|
if (fetchedLinks.length !== currentLinks.length) {
|
|
|
|
|
|
changed = true;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
for (i = 0; i < fetchedLinks.length; i++) {
|
|
|
|
|
|
if (fetchedLinks[i].getAttribute("href") !== currentLinks[i].getAttribute("href")) {
|
|
|
|
|
|
changed = true;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!changed) return;
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
if (sessionStorage.getItem("pjaxVerReload")) return; // 本会话已刷过
|
|
|
|
|
|
sessionStorage.setItem("pjaxVerReload", "1");
|
|
|
|
|
|
} catch (err) { /* 隐私模式等拿不到 sessionStorage:直接刷,概率极低 */ }
|
|
|
|
|
|
|
|
|
|
|
|
console.info("[pjax] 检测到样式表版本变化,整页刷新以加载新资源");
|
|
|
|
|
|
window.location.reload();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2026-10-07 21:41:58 +08:00
|
|
|
|
// UIKit 重新扫描(PJAX 必需)
|
|
|
|
|
|
// ─────────────────────────────────────────────────────────────
|
|
|
|
|
|
// UIKit 只在页面加载时做一次「全量 boot」:它遍历 document.body,把带
|
|
|
|
|
|
// uk-* 属性的元素逐个 connect 成组件。PJAX 换入的 DOM 是我们用
|
|
|
|
|
|
// innerHTML 塞进去的,UIKit 的 MutationObserver 虽然监听了 childList,
|
|
|
|
|
|
// 但因为「换入前属性就已存在」,observer 拿不到 attribute 的新增事件,
|
|
|
|
|
|
// 加上 PJAX 的替换发生在 UIKit 首次 boot 之后,组件就永远绑不上。
|
|
|
|
|
|
//
|
|
|
|
|
|
// 症状:uk-scrollspy 的元素停在 visibility:hidden(动画类的初始态),
|
|
|
|
|
|
// 下折叠的内容永久不可见,滚动也不会出现。
|
|
|
|
|
|
//
|
|
|
|
|
|
// 解法:换页后手动调一次 UIkit.update()。它会从传入节点向上走到
|
|
|
|
|
|
// document.body,再对整棵子树递归 connect —— 正好补上这次 boot。
|
|
|
|
|
|
function reinitUIKit(root) {
|
|
|
|
|
|
if (typeof window.UIkit === 'undefined' || typeof window.UIkit.update !== 'function') return;
|
|
|
|
|
|
var target = root || document.getElementById('pjax-container') || document.body;
|
|
|
|
|
|
try {
|
|
|
|
|
|
window.UIkit.update(target);
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
console.warn('UIkit.update failed:', e);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 暴露给页面脚本:动态插入带 uk-* 属性的内容后,调一次即可让 UIKit 生效
|
|
|
|
|
|
window.reinitUIKit = reinitUIKit;
|
|
|
|
|
|
|
2026-01-31 17:24:31 +08:00
|
|
|
|
// pjax预先加载代码
|
2024-07-26 14:22:52 +08:00
|
|
|
|
function pjax_reload() {
|
2026-01-31 19:24:22 +08:00
|
|
|
|
console.log("Pjax reload triggered");
|
2024-07-26 14:22:52 +08:00
|
|
|
|
// 给pjax容器加入css过渡动画
|
2026-01-31 19:24:22 +08:00
|
|
|
|
// var pjaxContainer = document.getElementById("pjax-container");
|
|
|
|
|
|
// if (pjaxContainer) pjaxContainer.classList.add("uk-animation-slide-bottom-small");
|
|
|
|
|
|
|
2024-07-26 14:22:52 +08:00
|
|
|
|
// 评论区过渡动画
|
2026-01-31 19:24:22 +08:00
|
|
|
|
var selectors = [
|
|
|
|
|
|
".comment-meta",
|
|
|
|
|
|
".comment-author vcard",
|
|
|
|
|
|
".comment-metadata",
|
|
|
|
|
|
".comment-content",
|
|
|
|
|
|
".reply"
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
selectors.forEach(function(selector) {
|
|
|
|
|
|
document.querySelectorAll(selector).forEach(function(el) {
|
|
|
|
|
|
el.setAttribute("uk-scrollspy", "cls: uk-animation-fade; delay: 100");
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2024-07-26 14:22:52 +08:00
|
|
|
|
// 说说页面过渡动画
|
2026-01-31 19:24:22 +08:00
|
|
|
|
var shuoshuoBody = document.getElementById("shuoshuo_body");
|
|
|
|
|
|
if (shuoshuoBody) {
|
|
|
|
|
|
shuoshuoBody.setAttribute("uk-scrollspy", "target: > .shuoshuo; cls: uk-animation-fade; delay: 250");
|
|
|
|
|
|
}
|
2024-07-26 14:22:52 +08:00
|
|
|
|
}
|
2026-01-31 19:24:22 +08:00
|
|
|
|
|
2026-05-20 14:33:05 +08:00
|
|
|
|
function refreshHeatmap() {
|
|
|
|
|
|
if (typeof renderHeatmap === 'function') {
|
|
|
|
|
|
try {
|
|
|
|
|
|
renderHeatmap();
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
console.error('renderHeatmap error:', e);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-07-26 14:22:52 +08:00
|
|
|
|
// pjax发送时期
|
|
|
|
|
|
document.addEventListener("pjax:send", function () {
|
|
|
|
|
|
// pjax动画减少圆圈动画
|
|
|
|
|
|
NProgress.configure({
|
|
|
|
|
|
showSpinner: false
|
|
|
|
|
|
});
|
|
|
|
|
|
// pjax执行动画开始
|
|
|
|
|
|
NProgress.start(); //加载动画效果开始
|
|
|
|
|
|
});
|
2026-01-31 19:24:22 +08:00
|
|
|
|
|
2024-07-26 14:22:52 +08:00
|
|
|
|
// Pjax 成功后,重新加载下面的函数
|
|
|
|
|
|
document.addEventListener("pjax:success", function () {
|
|
|
|
|
|
// 重载图片懒加载插件的js
|
2026-01-31 19:24:22 +08:00
|
|
|
|
if (typeof lazyLoadInit === 'function') {
|
|
|
|
|
|
lazyLoadInit({
|
|
|
|
|
|
// coverColor: "white",
|
|
|
|
|
|
// coverDiv: "<div style='display: flex; justify-content: center; align-items: center; height: 200px; color: #000000;'><span>优世界·一个记录生活点滴的小站</span></div>",
|
2026-02-02 20:38:58 +08:00
|
|
|
|
offsetBottom: 50,
|
|
|
|
|
|
offsetTopm: 50,
|
|
|
|
|
|
showTime: 1100,
|
|
|
|
|
|
queueInterval: 100
|
2026-01-31 19:24:22 +08:00
|
|
|
|
});
|
|
|
|
|
|
}
|
2024-07-26 14:22:52 +08:00
|
|
|
|
// 激活文章图片灯箱
|
2026-01-31 19:24:22 +08:00
|
|
|
|
if (window.ViewImage) {
|
|
|
|
|
|
ViewImage.init('.post-content img');
|
|
|
|
|
|
}
|
2026-05-25 00:03:50 +08:00
|
|
|
|
|
|
|
|
|
|
if (typeof window.refreshFloatingTools === 'function') {
|
|
|
|
|
|
window.refreshFloatingTools();
|
|
|
|
|
|
}
|
2024-07-26 14:22:52 +08:00
|
|
|
|
});
|
2026-01-31 19:24:22 +08:00
|
|
|
|
|
2024-07-26 14:22:52 +08:00
|
|
|
|
// pjax加载完成
|
2026-05-25 15:01:18 +08:00
|
|
|
|
document.addEventListener("pjax:complete", function () {
|
2026-06-02 16:26:38 +08:00
|
|
|
|
// 立即执行:进度条、基础 UI
|
|
|
|
|
|
if (typeof NProgress !== 'undefined') NProgress.done();
|
2026-01-31 19:24:22 +08:00
|
|
|
|
pjax_reload();
|
2026-05-25 15:01:18 +08:00
|
|
|
|
|
2026-10-07 21:41:58 +08:00
|
|
|
|
// ★ 关键:pjax_reload() 里刚给评论/说说等元素新加了 uk-scrollspy 属性,
|
|
|
|
|
|
// 此刻连同换入的整棵新 DOM 一起交给 UIKit 重新 boot一遍。
|
|
|
|
|
|
// 必须在 pjax_reload() 之后调用,否则新加的属性会被漏掉。
|
|
|
|
|
|
// (关于页的分节动画也走 UIKit scrollspy,所以同样靠这一步复活。)
|
|
|
|
|
|
reinitUIKit();
|
|
|
|
|
|
|
2026-06-03 12:29:56 +08:00
|
|
|
|
// 动态加载页面特定JS(PJAX适配)
|
|
|
|
|
|
// 检测当前页面是否为文章详情页,如果是则加载page-only.js
|
|
|
|
|
|
var currentPath = window.location.pathname;
|
|
|
|
|
|
var isArticlePage = document.querySelector('#Comments') !== null ||
|
|
|
|
|
|
document.querySelector('.post-content') !== null;
|
|
|
|
|
|
|
|
|
|
|
|
if (isArticlePage && !window._pageOnlyLoaded && window._pageOnlyScriptUrl) {
|
|
|
|
|
|
// 动态加载page-only.js(使用Hugo fingerprint后的正确URL)
|
|
|
|
|
|
var script = document.createElement('script');
|
|
|
|
|
|
script.src = window._pageOnlyScriptUrl;
|
|
|
|
|
|
script.onload = function() {
|
|
|
|
|
|
window._pageOnlyLoaded = true;
|
|
|
|
|
|
console.log('page-only.js loaded for PJAX navigation');
|
|
|
|
|
|
// 初始化Artalk等
|
|
|
|
|
|
if (typeof window.initArtalk === 'function') {
|
|
|
|
|
|
try { window.initArtalk(); } catch(e) { console.error('initArtalk error:', e); }
|
|
|
|
|
|
}
|
|
|
|
|
|
if (typeof window.initParagraphComments === 'function') {
|
|
|
|
|
|
try { window.initParagraphComments(); } catch(e) {}
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
document.body.appendChild(script);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-02 16:26:38 +08:00
|
|
|
|
// 下一帧执行:轻量初始化
|
|
|
|
|
|
requestAnimationFrame(function() {
|
|
|
|
|
|
if (typeof initCodeCopy === 'function') initCodeCopy();
|
|
|
|
|
|
if (typeof window.initSearch === 'function') {
|
|
|
|
|
|
try { window.initSearch(); } catch(e) {}
|
2026-01-31 22:52:19 +08:00
|
|
|
|
}
|
2026-06-02 16:26:38 +08:00
|
|
|
|
if (typeof window.refreshFloatingTools === 'function') {
|
|
|
|
|
|
window.refreshFloatingTools();
|
|
|
|
|
|
} else if (typeof window.initFloatingTools === 'function') {
|
|
|
|
|
|
try { window.initFloatingTools(); } catch(e) {}
|
|
|
|
|
|
}
|
|
|
|
|
|
// 文章动画
|
|
|
|
|
|
if (typeof window.initPostScrollspy === 'function') window.initPostScrollspy();
|
|
|
|
|
|
});
|
2026-01-31 22:52:19 +08:00
|
|
|
|
|
2026-06-02 16:26:38 +08:00
|
|
|
|
// 空闲时执行:非关键功能
|
|
|
|
|
|
var idle = window.requestIdleCallback || function(fn) { return setTimeout(fn, 200); };
|
|
|
|
|
|
idle(function() {
|
|
|
|
|
|
if (typeof window.initParagraphComments === 'function') {
|
|
|
|
|
|
try { window.initParagraphComments(); } catch(e) {}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (typeof window.initInfiniteScroll === 'function' && window.enableInfiniteScroll) {
|
|
|
|
|
|
window.initInfiniteScroll();
|
|
|
|
|
|
}
|
|
|
|
|
|
if (typeof window.initLinkStatus === 'function') {
|
|
|
|
|
|
try { window.initLinkStatus(); } catch(e) {}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (typeof window.initArtalk === 'function') {
|
|
|
|
|
|
try { window.initArtalk(); } catch(e) {}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (typeof window.bsz_fetch === 'function') {
|
|
|
|
|
|
try { window.bsz_fetch(); } catch(e) {}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (typeof window.initImageFrameReveal === 'function') {
|
|
|
|
|
|
try { window.initImageFrameReveal(); } catch(e) {}
|
|
|
|
|
|
}
|
|
|
|
|
|
// 链接卡片和中英文间距(DOM 扫描,非关键)
|
|
|
|
|
|
if (typeof window.initLinkify === 'function') window.initLinkify();
|
|
|
|
|
|
if (typeof window.initPangu === 'function') window.initPangu();
|
|
|
|
|
|
});
|
2026-05-20 14:33:05 +08:00
|
|
|
|
|
2026-06-02 16:26:38 +08:00
|
|
|
|
// 延迟:代码折叠
|
|
|
|
|
|
setTimeout(function() {
|
|
|
|
|
|
if (typeof window.initCodeFold === 'function') window.initCodeFold();
|
|
|
|
|
|
}, 300);
|
2024-07-26 14:22:52 +08:00
|
|
|
|
});
|