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("复制失败,请手动复制"); }); }
这样在代码区域右上角有一个复制按钮,点击复制之后,如果成功则系统剪贴板内有复制的内容,如果复制失败会弹窗和在浏览器控制台报错。而且,复制按钮本身的文字不会被复制。