chaihongjun.me

vue页面使用highlight.js代码高亮和Clipboard代码复制

Vue2和Vue3使用highlight.js进行代码高亮,Clipboard进行代码复制有一定差异,主要是this在vue3中不指向组件实例。

假设内容区域代码:

<article class="article-content" :title="article.title" id="article-content" v-html="article.content"></article>

页面的内是通过v-html渲染而来。

首先是安装这两个插件:

npm i clipboard
npm i highlight.js

然后是引入,不需要全站引入,则在需要使用的页面引入:

//DetailView.vue 会展示代码的页面
import hljs from "highlight.js";
import "highlight.js/styles/github-dark-dimmed.min.css"; // 选择你喜欢的主题样式
import ClipboardJS from "clipboard";

后续需要分Vue2和Vue3版本分别处理:

// Vue2
async mounted () {
// 代码高亮
await this.highlightCode();
// 初始化 Clipboard.js
await this.initClipboard();
// 监听内容变化
this.$watch(
    () => this.article.content, //article.content 是内容
    () => {
        this.$nextTick(() => {
            this.initClipboard();
        });
    }
);
},
methods:{
    //高亮代码
highlightCode() {
        hljs.configure({
            cssSelector: "pre", //修改默认的代码选择器
        });
        const blocks = document.querySelectorAll(".article-content pre");
        blocks.forEach((block) => {
            hljs.highlightElement(block);
            // 创建复制按钮
            const copyBtn = document.createElement("button");
            copyBtn.type = "button";
            copyBtn.className = "copy-btn";
            copyBtn.innerText = "copy";
            // 将按钮插入到 pre 标签内部
            block.appendChild(copyBtn);
        });
    },
    // 初始化剪切板
    initClipboard() {
        // 销毁之前的实例
        if (this.clipboard) {
            this.clipboard.destroy();
        }
        // 初始化 Clipboard.js
        this.clipboard = new ClipboardJS(".copy-btn", {
            text: function(trigger) {
                // 找到对应的 pre 标签
                const preElement = trigger.parentElement;
                // 克隆 pre 标签
                const codeText = preElement.cloneNode(true);
                // 移除 pre 标签内的所有 .copy-btn 元素
                codeText.querySelectorAll(".copy-btn").forEach((btn) => btn.remove());
                // 返回克隆后的内容的文本
                return codeText.innerText;
            },
        });
        // 处理复制成功事件
        this.clipboard.on("success", (e) => {
            //console.log("Text copied to clipboard:", e.text);
            // alert("代码已复制到剪贴板");
        });
        // 处理复制失败事件
        this.clipboard.on("error", (e) => {
            console.error("Failed to copy text: ", e);
            alert("复制失败,请手动复制");
        });
    }
}
//vue3
import { ref, onMounted, watch, nextTick } from 'vue'
// 声明 clipboard 实例的响应式变量
const clipboard = ref(null)
//监控文章内容变化
watch(
  () => article.value.content,
  () => {
    nextTick(() => {
      initClipboard();
    });
  }
);
onMounted(async () => {
  // 代码高亮
  await highlightCode();
  // 初始化 Clipboard.js
  await initClipboard();
});

//高亮代码
function highlightCode() {
    //由于highlight.js 默认的代码识别是 <pre><code>...</code></pre>
    //这里根据实际情况<pre>...</pre> 修改
    hljs.configure({
        cssSelector: "pre",
    });
    //一篇文章内的多个代码区域
    const blocks = document.querySelectorAll(".article-content pre");

    blocks.forEach((block) => {
        // 对每个代码区域启用代码高亮
        hljs.highlightElement(block);
        // 创建复制按钮
        const copyBtn = document.createElement("button");
        copyBtn.type = "button";
        copyBtn.className = "copy-btn";
        copyBtn.innerText = "copy";
        // 将按钮插入到 pre 标签内部(尾部)
        block.appendChild(copyBtn);
    });

}


// 初始化剪切板
function initClipboard() {
    // 销毁之前的实例
    if (clipboard.value) {
        clipboard.value.destroy();
    }
    // 初始化 Clipboard.js
    clipboard.value = new ClipboardJS(".copy-btn", {
        text: function(trigger) {
            // 找到对应的 pre 标签
            const preElement = trigger.parentElement;
            // 克隆 pre 标签
            const codeText = preElement.cloneNode(true);
            // 移除 pre 标签内的所有 .copy-btn 元素
            codeText.querySelectorAll(".copy-btn").forEach((btn) => btn.remove());
            // 返回克隆后的内容的文本
            return codeText.innerText;
        },
    });
    // 处理复制成功事件
    clipboard.value.on("success", (e) => {
        //console.log("Text copied to clipboard:", e.text);
        // alert("代码已复制到剪贴板");
    });
    // 处理复制失败事件
    clipboard.value.on("error", (e) => {
        console.error("Failed to copy text: ", e);
        alert("复制失败,请手动复制");
    });
}

这样在代码区域右上角有一个复制按钮,点击复制之后,如果成功则系统剪贴板内有复制的内容,如果复制失败会弹窗和在浏览器控制台报错。而且,复制按钮本身的文字不会被复制。

知识共享许可协议本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。作者:柴宏俊»