为 Typecho 的 Code Block 添加 Copy 按钮

2019-08-18T13:17:00

之前为了隐藏大段代码写了 Typecho 简单实现点击复制,缺点是转义字符会被解析,无法原样复制。今天无意间看到 JS 代码块复制按钮,稍微改了下,发现转义字符也能完美复制,下面介绍下 Mirages 主题的使用步骤,其他主题改改选择器名称就行了。

使用步骤

关闭 PJAX

开启 PJAX 后无法触发代码依赖的 DOMContentLoaded 及其他事件,因此需要关闭。Mirages 主题默认是关闭的,如果已经开启,可前往 控制台 - 设置外观 - PJAX(BETA) 中关闭。

PJAX 问题已解决,原来主题作者预留了回调接口,我真是眼瞎。现在只要在 控制台 - 设置外观 - PJAX(BETA) - PJAX RELOAD 里添加 __addCodeCopyBtn(); 即可。

引入 JS 和 CSS 代码

将下面的代码添加到主题的 header.php 中或前往 控制台 - 设置外观 - 自定义扩展,将它们添加到 自定义 HTML 元素拓展 - 标签: head 头部 (meta 元素后)

<style>
    .btn-code-copy {
        line-height: 0.6;
        color: rgb(145, 145, 145);
        position: absolute;
        right: .2em;
        top: .2em;
        z-index: 2;
        transition: .5s;
    }

    .btn-code-copy:hover {
        color: rgb(87, 87, 87);
        cursor: pointer;
    }

    .btn-code-copy:active {
        color: rgb(87, 87, 87);
    }
</style>
<script>
    document.addEventListener('DOMContentLoaded', __addCodeCopyBtn);

    function __copyTextContent(source) {
        let result = false;
        let target = document.createElement('pre');
        target.style.opacity = '0';
        target.textContent = source.textContent;
        document.body.appendChild(target);
        try {
            let range = document.createRange();
            range.selectNode(target);
            window.getSelection().removeAllRanges();
            window.getSelection().addRange(range);
            document.execCommand('copy');
            window.getSelection().removeAllRanges();
            result = true;
        } catch (e) {}
        document.body.removeChild(target);
        return result;
    }

    function __addCodeCopyBtn() {
        document.querySelectorAll('pre').forEach(pre => {
            let code = pre.querySelector('code');
            if (code) {
                let preParent = pre.parentElement;
                let newPreParent = document.createElement('div');
                newPreParent.style = 'position: relative';
                preParent.insertBefore(newPreParent, pre);

                let copyBtn = document.createElement('div');
                copyBtn.innerHTML = 'copy';
                copyBtn.className = 'btn-code-copy';
                copyBtn.addEventListener("click", () => {
                    copyBtn.innerHTML = __copyTextContent(code) ? 'success' : 'failure';
                    setTimeout(() => copyBtn.innerHTML = 'copy', 250);
                });

                newPreParent.appendChild(copyBtn);
                newPreParent.appendChild(pre);
            }
        });
    }
</script>

遗留问题

原作者遗留了一个问题,即拉动横向滚动条时,copy 按钮会跟着滚动,你可以在主题设置中开启自动换行,我的代码估计没有人看,有时间再解决吧。

更新日志

2019/08/18 14:35 解决 COPY 横向滚动的问题
2019/09/07 21:02 解决 PJAX 下,事件无法触发的问题

当前页面是本站的「Baidu MIP」版。发表评论请点击:完整版 »