Featured image of post 解决引入Pjax带来的各种问题

解决引入Pjax带来的各种问题

2497 字

解决URL出现随机参数?t=xxx、twikoo评论、PhotoSwipe等问题

前言:

本文将详细介绍如何在 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 重新引入 PhotoSwipeJSCSS

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 带来的各种问题!如果你有任何问题或建议,欢迎在评论区留言交流。

使用 Hugo 构建
主题 StackJimmy 设计