MENU

为 Typecho 的 Code Block 添加 Copy 按钮

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

使用步骤

关闭 PJAX

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

引入 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>
    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;
    }

    document.addEventListener('DOMContentLoaded', () => {
        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", ((btn, code) => {
                        return () => {
                            if (__copyTextContent(code)) {
                                btn.innerHTML = 'success';
                            } else {
                                btn.innerHTML = 'failure';
                            }
                            setTimeout(() => {
                                btn.innerHTML = 'copy';
                            }, 250);
                        };
                    })(copyBtn, code)
                );

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

遗留问题

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

0:00