导航菜单

MoOx/Pjax 官方说明

轻松在任何网站上启用快速的AJAX导航(使用pushState() + XHR)

MoOx/Pjax(以下简称Pjax)是一个独立的JavaScript模块,使用AJAX(XmlHttpRequest)和pushState()来提供快速的浏览体验。

Pjax库方便你改善传统网站(服务端渲染的或者静态网站)的用户体验,使用户感觉像在使用应用程序,尤其是那些宽带质量差的用户。

不再需要完整的页面重新加载。不会创建多个HTTP请求

Pjax不依赖于其他库,如jQuery或类似的库,完全使用原生JS编写

初步改造

1.引入 JS(这里采用国内的CDN),建议修改footer.php引入,在</body>之前插入即可

<script src="https://jsd.onmicrosoft.cn//npm/pjax@0.2.8/pjax.min.js"></script>
<script>
    document.addEventListener('pjax:send', () => {
        NProgress.start();
    });
    document.addEventListener('pjax:complete', () => {
        NProgress.done();
    });
    let pjax = new Pjax({
        elements: 'a[href^="<?php $this->options->siteUrl(); ?>"]:not(a[target="_blank"], a[no-pjax], a[href^="<?php $this->options->adminUrl(); ?>"])',
        selectors: [
            "title",
            ".main-menu",
            "main",
            "#logout",
        ]
    });
    // 这里插入其他代码
</script>

注意这里要修改selectors,selectors是告诉脚本 Pjax 加载的新页面那些部分的内容要替换到网页上,格式为css选择器。比如title是网页标题;比如退出链接,我给加了个IDlogout,所以是#logout,如果导航菜单做了高亮当前也也是需要替换的,至于正文内容就更不用说了。

加载动画

加载动画是让用户有网页正在加载的感觉,推荐使用NProgress,或者你自己写也行。反正我用的是 Nprogress。
1.引入 Nprogress,放在 Pjax 脚本之前

<link href="https://cdn.bootcdn.net/ajax/libs/nprogress/0.2.0/nprogress.min.css" rel="stylesheet">
<script src="https://cdn.bootcdn.net/ajax/libs/nprogress/0.2.0/nprogress.min.js"></script>

2.然后在 Pjax 初始化脚本之后插入

document.addEventListener('pjax:send', () => {
    NProgress.start();
});
document.addEventListener('pjax:complete', () => {
    NProgress.done();
});

pjax:sendpjax刚开始发送网络请求时触发的事件
pjax:complete是pjax完成后触发的事件
如果是使用自定义动画,请将NProgress.start()NProgress.done()替换为自己的代码

修复一些问题问题

1.开启了 Pjax 之后发现表情无法加载了,回到顶部不换用啦,Lazyload不加载图片啦,点赞弹窗不可用啦等等的问题都是因为Pjax只是替换部分页面内容,JS 那些还是原来老的,只能在PJAX完成的时候触发一下重载事件。

document.addEventListener('pjax:complete', () => {
    NProgress.done();
    new OwO(); // 重新初始化表情
    GoTop.init(); // 回到顶部重载
    LayzloadInstance.update() // Lazyload 重载
});

2.开启Pjax可以评论无法回复
我观察了一下,是因为 Typecho 默认输出的 评论 JS 是写死 comment-id 的,只能屏蔽原来的 JS 脚本,改成自动获取 ID的。
修改header.php$this->header()修改为$this->header('commentReply='),这样就可以屏蔽原来的输出。
Header 其他参数参见


屏蔽了评论 JS 输出就会导致无法评论,所以得增加修改版的评论JS,插入到 PJAX 初始化脚本后面即可(就// 这里插入其他代码那里)

window.TypechoComment = {
    dom: function (id) {
        return document.getElementById(id);
    },

    query: function (sel) {
        return document.querySelector(sel);
    },

    create: function (tag, attr) {
        var el = document.createElement(tag);

        for (var key in attr) {
            el.setAttribute(key, attr[key]);
        }

        return el;
    },

    reply: function (cid, coid) {
        var comment = this.dom(cid), parent = comment.parentNode,
            response = this.query(".comment-respond"), input = this.dom('comment-parent'),
            form = 'form' == response.tagName ? response : response.getElementsByTagName('form')[0],
            textarea = response.getElementsByTagName('textarea')[0];

        if (null == input) {
            input = this.create('input', {
                'type': 'hidden',
                'name': 'parent',
                'id': 'comment-parent'
            });

            form.appendChild(input);
        }

        input.setAttribute('value', coid);

        if (null == this.dom('comment-form-place-holder')) {
            var holder = this.create('div', {
                'id': 'comment-form-place-holder'
            });

            response.parentNode.insertBefore(holder, response);
        }

        comment.appendChild(response);

        this.dom('cancel-comment-reply-link').style.display = '';

        if (null != textarea && 'text' == textarea.name) {
            textarea.focus();
        }

        return false;
    },

    cancelReply: function () {
        var response = this.query('.comment-respond')
        holder = this.dom('comment-form-place-holder'), input = this.dom('comment-parent');

        if (null != input) {
            input.parentNode.removeChild(input);
        }

        if (null == holder) {
            return true;
        }

        this.dom('cancel-comment-reply-link').style.display = 'none';
        holder.parentNode.insertBefore(response, holder);
        return false;
    }
};

至此!享受你的pjax无刷新技术吧!