PJAX.png

I. 主理人说

Typecho 优化任重道远。

代码复制按钮的 JavaScript 文件贡献来自 兔子昂,在此表示感谢。如果你使用了 handsome 主题,并启用了 PJAX 主题增强功能,则在添加代码复制按钮结束后应再添加 PJAX 回调函数以确保用户可以在任意页面得到 JavaScript 执行( codecopy.js 执行,而不是需要额外刷新页面才能得到想要的结果)。

II. 复制按钮效果

代码复制按钮.png

III. 如何添加复制按钮

Typecho 好就好在简单,高度可定义。

新建 codepocy.js

新建 codepocy.js ,内容为:

//html5 给typecho添加 复制代码 功能 
// by 兔子昂
var codeblocks = document.getElementsByTagName("pre")
//循环每个pre代码块,并添加 复制代码

for (var i = 0; i < codeblocks.length; i++) {
    //显示 复制代码 按钮
    currentCode = codeblocks[i]
    currentCode.style = "position: relative;"
    var copy = document.createElement("div")
    copy.style = "position: absolute;right: 4px;\
    top: 4px;background-color: white;padding: 2px 8px;\
    margin: 8px;border-radius: 4px;cursor: pointer;\
    box-shadow: 0 2px 4px rgba(0,0,0,0.05), 0 2px 4px rgba(0,0,0,0.05);"
    copy.innerHTML = "复制"
    currentCode.appendChild(copy)
    //让所有 "复制"按钮 全部隐藏
    copy.style.visibility = "hidden"
}


for (var i = 0; i < codeblocks.length; i++) {


    !function (i) {
        //鼠标移到代码块,就显示按钮
        codeblocks[i].onmouseover = function () {
            codeblocks[i].childNodes[1].style.visibility = "visible"
        }

        //执行 复制代码 功能
        function copyArticle(event) {
            const range = document.createRange();

            //范围是 code,不包括刚才创建的div
            range.selectNode(codeblocks[i].childNodes[0]);

            const selection = window.getSelection();
            if (selection.rangeCount > 0) selection.removeAllRanges();
            selection.addRange(range);
            document.execCommand('copy');

            codeblocks[i].childNodes[1].innerHTML = "复制成功"
            setTimeout(function () {
                codeblocks[i].childNodes[1].innerHTML = "复制"
            }, 1000);
            //清除选择区
            if (selection.rangeCount > 0) selection.removeAllRanges(); 0
        }
        codeblocks[i].childNodes[1].addEventListener('click', copyArticle, false);

    }(i);

    !function (i) {
        //鼠标从代码块移开 则不显示复制代码按钮
        codeblocks[i].onmouseout = function () {
            codeblocks[i].childNodes[1].style.visibility = "hidden"
        }
    }(i);
}

引用codecopy.js

在主题文件内如博主的 /usr/themes/handsome/ 找到 footer.php(建议在footer.php内进行引用,有利于页面渲染避免阻塞)或 header.php , 打开其中任意一个文件,在</body> 前或者在 <body 后(即<body>...</body>间)引用 codecopy.js;

<script type="text/javascript". src="https://limbopro.com/usr/themes/handsome/codecopy.js">

效果如下所示:

<?php $this->options->bottomHtml(); ?>
<script type="text/javascript". src="https://limbopro.com/usr/themes/handsome/codecopy.js">
</body>
</html><!--html end-->

IV. 设置 PJAX 回调函数

回调又可以称为“重载”,重新加载。

假设你的 codecopy.js 文件放在网站根目录下如 /usr/themes/handsome/codecopy.js;且你启用了 PJAX 增强功能。则你从首页或任意页面进入一个新页面(这个页面有代码)时,在新页面下极有可能看不到这个复制按钮

这正是博主所遇到的问题,PJAX已缓存JS文件,但打开新页面时不会重新执行,要刷新一下页面才能看到JS执行效果。

pjax采用的是异步请求资源(实现全站无刷新访问),也就是每次请求数据不是重新获取整个页面的数据而是只会获取#pjax-container容器里面的数据。所以如果一个函数在容器外面(如多说加载函数),在A页面没有,B又需要的话,那么从A页面进入B页面,这个函数就不会执行。必须回调这个函数

注: 不同主题对于#pjax-container选取不一样以及结构可能不同解决方法会有不同(一般是差不多的)

via 友人C:typecho博客实现pjax

设置 PJAX 回调函数(重新加载执行 JavaScript 脚本);

// 官方说明摘引
// Load an execute scripts using standard script request.
//
// Avoids jQuery's traditional $.getScript which does a XHR request and
// globalEval.
//
// scripts - jQuery object of script Elements
//
// Returns nothing.

方法1

修改 jquery.pjax.min.js 文件;

# 进入主题目录
$ cd /home/wwwroot/typecho/usr/themes/handsome/
$ grep "pjax:complete" -rl --include "*.js" ./
./assets/js/core.min.js
./assets/js/features/jquery.pjax.min.js

handsome 主题已内置 PJAX 增强(网站打开如丝般顺滑),在主题外观设置中启用即可。

PJAX-Handsome主题.png

打开 jquery.pjax.min.js 文件,大约在236行

        options.complete = function(xhr, textStatus) {
            if (timeoutTimer)
                clearTimeout(timeoutTimer)
            fire('pjax:complete', [xhr, textStatus, options]) //在 pjax:complete 后插入回调函数
            $.getScript("/usr/themes/handsome/codecopy.js") //在 pjax:end 前插入回调函数
            $.getScript("https://platform.twitter.com/widgets.js") //在 pjax:end 前插入回调函数
            fire('pjax:end', [xhr, options])
        }

P.S 为什么我这里额外增加了 https://platform.twitter.com/widgets.js ?因为我为博客侧边栏增加了一栏来放 Twitter发布页的内容,使用 PJAX 后,需要额外刷新才能加载内容,这完全是不可接受的。

方法2

设置 PJAX 回调函数.png

$.getScript("https://platform.twitter.com/widgets.js") //在 pjax:end 前插入回调函数

主题-外观设置-PJAX回调函数;

V. 附注

关于 PJAX:

jQuery ajax - getScript() 方法

最后修改:2023 年 03 月 18 日 03 : 57 PM