分類
標籤
.env AI Arc Arm Astro BigQuery btop Certbot Chrome CICD Cookie CORS CSS cURL DataTables defineExpose DevOps Docker Draggable Fetch API Gamania Git GitLab Google Calendar Google Cloud Summit Google Tag Manager GSAP HTML iCal inject JavaScript Laravel Less LINE Llama 3 Masonry Meta Nginx Nginx UI O(log n) Ollama OpenSSL Oracle OrbStack PHP Pinia Pixel Postman provide Proxyman Raycast requestAnimationFrame script setup Server Session Sitemap Socialite SSL TablePlus Termius Valet Vertex AI Visual Studio Code Vite Vue 3 Vue2 Vue3 Vuex Warp Webpack Yahoo Calendar Zeabur 二分搜尋 元件溝通 前端開發 動畫效果 峰值體驗 廣告 性能優化 打包 推薦系統 搜尋 時間複雜度 演算法 瀑布流排版 父子元件 環境變數 程式碼複製按鈕 系統監控 網站地圖 網頁開發 自動化部署 螢幕刷新率 語言模型 資訊檢索 跨域請求 轉化率 開發工具 陣列 電商 電子商務
614 字
3 分鐘
在 Astro 中添加程式碼區塊複製按鈕
在 Astro 中添加程式碼區塊複製按鈕,可以讓讀者更方便地複製程式碼。以下是在 Astro 中添加程式碼區塊複製按鈕的環境與方法:
環境
- Fuwari 主題 Waiting for api.github.com...
- Tailwind CSS
方法
以 Fuwari 主題為例,在 /src/components/misc/Markdown.astro
中添加以下完成的程式碼:
<script>
const observer = new MutationObserver(addPreCopyButton);
observer.observe(document.body, { childList: true, subtree: true });
document.addEventListener("DOMContentLoaded", addPreCopyButton);
function addPreCopyButton() {
observer.disconnect();
let codeBlocks = Array.from(document.querySelectorAll("pre"));
for (let codeBlock of codeBlocks) {
if (codeBlock.parentElement?.nodeName === "DIV" && codeBlock.parentElement?.classList.contains("code-block")) continue;
let wrapper = document.createElement("div");
wrapper.className = "relative code-block";
let copyButton = document.createElement("button");
copyButton.className = "copy-code btn-regular absolute top-0 right-0 text-sm px-3 py-2 rounded-bl-lg rounded-tr-lg opacity-75 hover:opacity-100 transition-all duration-200 ease-in-out";
copyButton.textContent = 'Copy';
codeBlock.setAttribute("tabindex", "0");
if (codeBlock.parentNode) {
codeBlock.parentNode.insertBefore(wrapper, codeBlock);
}
wrapper.appendChild(codeBlock);
wrapper.appendChild(copyButton);
copyButton.addEventListener("click", async () => {
let text = codeBlock?.querySelector("code")?.innerText;
await navigator.clipboard.writeText(text);
copyButton.textContent = 'Code Copied';
copyButton.classList.toggle("opacity-100");
setTimeout(() => {
copyButton.textContent = 'Copy';
copyButton.classList.toggle("opacity-100");
}, 700);
});
}
observer.observe(document.body, { childList: true, subtree: true });
}
</script>
這邊以 Tailwind CSS 的寫法做範例,你可以根據需求調整 CSS 樣式與寫法。
遇到的狀況
在 Astro 的 JavaScript 中,只有在頁面載入時才會載入一次。這導致了一個問題:當從一個頁面切換到另一個頁面時,JavaScript 代碼不會重新載入,因此無法單獨使用 window.addEventListener("load", (event) => {});
事件來執行 addPreCopyButton
。
最初的解決方案是在網址切換時重新執行 addPreCopyButton
。然而,這種方法存在一些問題。當網址切換時,無法確定畫面是否已經完成渲染,可能導致無法正確添加複製按鈕。即使使用 setTimeout 延遲執行,仍無法確定畫面是否已經渲染完成。
以下是原始解決方案所使用的程式碼:
const originalPushState = history.pushState;
const originalReplaceState = history.replaceState;
history.pushState = function() {
originalPushState.apply(this, arguments);
checkURL();
};
history.replaceState = function() {
originalReplaceState.apply(this, arguments);
checkURL();
};
window.onpopstate = function() {
checkURL();
};
function checkURL() {
if (window.location.pathname.startsWith('/posts/')) {
console.log("URL changed");
}
}
根據我的記憶,可以使用 MutationObserver 來監聽畫面變化。因此,我們可以改用 MutationObserver 來監聽畫面變化,並在變化發生時執行 addPreCopyButton。
以下是使用 MutationObserver 的方法:
const observer = new MutationObserver(function (mutations) {
console.log(mutations);
});
const div = document.querySelector("div");
observer.observe(div, {
childList: true,
attributes: true,
characterData: true,
});
在實際執行 addPreCopyButton 時,我們首先斷開 observer 的監聽,以免在添加複製按鈕時再次觸發 observer,造成無限迴圈。待添加複製按鈕完成後,再重新啟動 observer 的監聽。
如果你有更好的解決方案,歡迎聯絡我~
參考資料:
在 Astro 中添加程式碼區塊複製按鈕
https://laplusda.com/posts/astro-code-copy-button/