前言:
本文将详细介绍如何在 Hugo-Stack 主题中引入 PJAX,并解决由此带来的各种问题,包括 URL 随机参数、评论系统、图片放大等功能异常。我们将逐一分析问题原因并提供解决方案。
1. 引入Pjax
PJAX (PushState + AJAX) 是一种实现无刷新页面加载的技术,可以提升用户体验。它主要分为两个版本:带 JQuery 和不带 JQuery 的版本,本文使用的是不带 JQuery 的版本。
下面我们直接在 layouts/partials/footer/custom.html 中添加以下代码来引入 PJAX:
1
2
3
4
5
6
7
8
9
| <!-- 【custom.html】 -->
<script src="https://cdn.jsdelivr.net/npm/pjax/pjax.min.js"></script>
<script>
var pjax = new Pjax({
selectors: [
".main-container" //告诉 PJAX 只替换页面中的这个 DOM 区域
]
})
</script>
|
需要注意的是,PJAX 只会替换 HTML,不会自动执行页面里的 <script>。基本引入 PJAX 后,下面我们将解决它带来的各种问题。
2. 解决问题
2.1 URL路径修复
问题描述
URL 后面多出一个参数 ?t=xxx 时间戳。
产生原因
PJAX 默认会在请求 URL 后加一个随机参数(例如 ?_pjax=xxxx 或者 ?t=xxx)来防止缓存。
修复好处
- 唯一的、规范的 URL,SEO 不受影响
- 搜索引擎能正确识别,不会重复收录
解决思路
使用 PJAX 内置的参数 cacheBust 或者自写函数获取当前路径识别后去除。
2.1.1 引入 cacheBust
设置 cacheBust: false 表示不加随机参数,让浏览器/服务器缓存生效。
- 好处:页面切换更快(利用缓存)
- 坏处:如果内容有更新,可能短时间内看不到最新版本(因为有缓存)
在 layouts/partials/footer/custom.html 中引入 cacheBust: false:
1
2
3
4
5
6
| <script>
var pjax = new Pjax({
//其他...
cacheBust: false,
});
</script>
|
2.1.2 自写函数去除
同样在 layouts/partials/footer/custom.html 中引入以下代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| <script>
// -------- 去掉PJAX 脚本给 URL 加上的时间戳 ?t=xxxx --------
function removeTParam() {
if (window.location.search.includes("?t=")) {
history.replaceState({}, "", window.location.pathname);
}
}
// 首次加载时立即去掉
removeTParam();
document.addEventListener('pjax:send', () => {
removeTParam();
//其他...
});
document.addEventListener('pjax:complete', () => {
removeTParam();
//其他...
});
</script>
|
2.2 文章样式修复
参考相关帖子:莱特雷-letere 文章样式修复
修改 layouts/partials/footer/custom.html,添加以下代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| <script>
pjax._handleResponse = pjax.handleResponse;
pjax.handleResponse = function(responseText, request, href, options) {
if (request.responseText.match("<html")) {
if (responseText) {
// 将新页面的html字符串解析成DOM对象
let newDom = new DOMParser().parseFromString(responseText, 'text/html');
// 获取新页面中body的className,并设置回当前页面
let bodyClass = newDom.body.className;
document.body.setAttribute("class", bodyClass)
}
// 放行,交给pjax自己处理
pjax._handleResponse(responseText, request, href, options);
} else {
// handle non-HTML response here
}
}
</script>
|
2.3 主题切换修复
参考相关帖子:莱特雷-letere 主题切换修复
修改 layouts/partials/footer/custom.html,添加以下代码:
1
2
3
4
5
6
| <script>
document.addEventListener('pjax:complete', () => {
// Stack脚本初始化
window.Stack.init();
})
</script>
|
2.4 文章搜索修复
参考相关帖子:莱特雷-letere 文章搜索修复
2.4.1 修改 search.tsx
修改 assets/ts/search.tsx 代码,封装方法并 export:
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
| /**
* 记得把window.addEventListener('load' ...这部分代码注释掉
* 初始化工作交给Stack.init()处理了,不需要这个了
*/
function searchInit() {
let search = document.querySelector('.search-result');
if (search) {
const searchForm = document.querySelector('.search-form') as HTMLFormElement,
searchInput = searchForm.querySelector('input') as HTMLInputElement,
searchResultList = document.querySelector('.search-result--list') as HTMLDivElement,
searchResultTitle = document.querySelector('.search-result--title') as HTMLHeadingElement;
new Search({
form: searchForm,
input: searchInput,
list: searchResultList,
resultTitle: searchResultTitle,
resultTitleTemplate: window.searchResultTitleTemplate
});
}
}
export {
searchInit
}
|
2.4.2 修改 main.ts
修改 assets/ts/main.ts,引入搜索初始化方法并调用:
1
2
3
4
5
6
7
8
| import { searchInit } from "ts/search";
let Stack = {
init: () => {
//其他...
// 调用search脚本初始化方法
searchInit();
}
}
|
2.5 搜索内容跳转修复
参考相关帖子:莱特雷-letere 搜索内容跳转修复
修改 assets/ts/search.tsx,在动态渲染数据方法末尾让 PJAX 重新解析文档:
1
2
3
4
5
6
7
8
9
| private async doSearch(keywords: string[]) {
...
/*
方法末尾,让pjax重新解析文档数据,识别动态渲染的数据
虽然当前文件没有pjax对象,但最后静态页面会生成一个整体的js文件
pjax对象那时就能识别到,就可成功调用
*/
pjax.refresh(document);
}
|
2.6 KaTeX修复
参考相关帖子:莱特雷-letere KaTeX修复
2.6.1 添加标识元素
修改 layouts/partials/article/components/math.html,添加一个元素标签,便于判断文档是否使用了 KaTeX:
1
| <div class="math-katex"></div>
|
2.6.2 添加初始化脚本
在 layouts/partials/footer/custom.html 中引入以下代码:
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
| <script>
async function renderKaTeX() {
// 判断当前页面是否有KateX
let katex = document.querySelector(".math-katex");
if (!katex) {
return;
}
// 等待函数加载成功后,再执行渲染方法
while (typeof renderMathInElement !== 'function') {
await delay(500);
}
// KaTeX渲染方法
renderMathInElement(document.body, {
delimiters: [
{ left: "$$", right: "$$", display: true },
{ left: "$", right: "$", display: false },
{ left: "\\(", right: "\\)", display: false },
{ left: "\\[", right: "\\]", display: true }
],
ignoredClasses: ["gist"]
});
}
/**
* 同步延迟
*/
function delay(time) {
return new Promise(resolve => {
setTimeout(resolve, time)
})
}
document.addEventListener('pjax:complete', () => {
renderKaTeX();
})
</script>
|
2.7 twikoo评论修复
引入 PJAX 导致 twikoo 评论区出现的问题,可以参考另外一篇帖子解决:Pjax导致Twikoo出现的问题
2.8 PhotoSwipe修复
问题描述
- 调试台出现不知道
photoswipe 是什么报错 - 点击图片后放大到整个页面后关闭,整个页面被 PJAX 刷新,并且定位到上一次打开图片的地方
产生原因
- 通过 PJAX 刷新页面或者说被刷新的区域刚好覆盖掉
photoswipe 初始化的 JS,没有重新初始化 - 点击放大图片后路径会变化,在此页面的路径加上
&gid=1&pid=18 这种,退出恢复原路径,路径有变化,PJAX 执行
解决思路
- 在
head 或者 footer 再次导入 photoswipe 的 JS - 想办法去掉打开图片的路径,路径没变化 PJAX 就不会再执行
具体步骤
2.8.1 重新引入 PhotoSwipe
在 layouts/partials/footer/custom.html 重新引入 PhotoSwipe 的 JS 和 CSS:
1
2
| {{- /* 引入 PhotoSwipe CSS/JS */ -}}
{{- partial "helper/external" (dict "Context" . "Namespace" "PhotoSwipe") -}}
|
2.8.2 禁用 URL HASH
在主题源码中找到 assets/ts/gallery.ts,找到相关函数,添加禁止 URL HASH 代码:
1
2
| history: false, // ✅ 禁用 URL hash
focus: false, // ✅ 关闭后不自动聚焦
|
2.9 backtop返回顶部按钮修复
[待补充]
2.10 toc修复
[待补充]
总结
通过以上步骤,我们解决了引入 PJAX 后带来的大部分问题,包括 URL 随机参数、文章样式、主题切换、搜索功能、KaTeX 渲染、评论系统和图片放大等。这些修复措施确保了在享受 PJAX 带来的无刷新体验的同时,网站的各项功能仍能正常工作。
需要注意的是,PJAX 的引入可能会与一些动态内容或脚本产生冲突,因此在使用过程中需要仔细测试各项功能。如果遇到本文未覆盖的问题,建议阅读相关源码或参考更多资料进行修复。
希望这篇教程能帮助你顺利解决 PJAX 带来的各种问题!如果你有任何问题或建议,欢迎在评论区留言交流。