juejin.user.js
· 4.2 KiB · JavaScript
Ham
// ==UserScript==
// @name 掘金复制代码段
// @namespace https://docs.scriptcat.org/
// @version 0.1.0
// @description 免登录复制掘金代码片段
// @author You
// @match https://juejin.cn/post/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=juejin.cn
// @downloadURL https://gist.asfd.cn/jetsung/juejin/raw/HEAD/juejin.user.js
// @updateURL https://gist.asfd.cn/jetsung/juejin/raw/HEAD/juejin.user.js
// @grant none
// ==/UserScript==
(function() {
'use strict';
// 自定义按钮样式
const customBtnStyle = {
display: 'inline-block',
padding: '2px 10px',
marginLeft: '8px',
fontSize: '13px',
color: '#fff',
backgroundColor: '#007fff',
borderRadius: '6px',
cursor: 'pointer',
userSelect: 'none',
transition: 'all 0.3s',
boxShadow: '0 2px 4px rgba(0,0,0,0.1)'
};
function addCustomCopyButton() {
document.querySelectorAll('.code-block-extension-header').forEach(header => {
const headerRight = header.querySelector('.code-block-extension-headerRight');
if (!headerRight || headerRight.querySelector('.juejin-custom-copy-btn')) return;
// 清空右侧所有原有按钮
headerRight.innerHTML = '';
// 创建自定义按钮
const copyBtn = document.createElement('div');
copyBtn.className = 'juejin-custom-copy-btn';
copyBtn.textContent = '复制代码段';
Object.assign(copyBtn.style, customBtnStyle);
// 悬停与成功效果
copyBtn.addEventListener('mouseenter', () => copyBtn.style.backgroundColor = '#0066cc');
copyBtn.addEventListener('mouseleave', () => {
if (copyBtn.textContent !== '复制成功') copyBtn.style.backgroundColor = '#007fff';
});
headerRight.appendChild(copyBtn);
// 复制逻辑(更稳健的纯文本提取)
copyBtn.addEventListener('click', async () => {
const codeContainer = header.parentElement.querySelector('pre code') ||
header.nextElementSibling?.querySelector('code') ||
header.parentElement.querySelector('code.hljs');
if (!codeContainer) {
copyBtn.textContent = '无代码';
setTimeout(() => copyBtn.textContent = '复制代码段', 2000);
return;
}
let pureCode = '';
// 优先尝试直接取 code 的纯文本(最干净)
if (codeContainer.textContent) {
pureCode = codeContainer.textContent.trim();
} else {
// 备选:逐行提取
const lines = Array.from(codeContainer.querySelectorAll('div, span, .code-block-extension-codeLine'))
.map(el => el.textContent || '');
pureCode = lines.join('\n').trim();
}
// 去除可能的行号前缀(如果还有残留)
pureCode = pureCode.replace(/^\s*\d+\s*/gm, '').trim();
try {
await navigator.clipboard.writeText(pureCode);
copyBtn.textContent = '复制成功 ✓';
copyBtn.style.backgroundColor = '#52c41a';
setTimeout(() => {
copyBtn.textContent = '复制代码段';
copyBtn.style.backgroundColor = '#007fff';
}, 2000);
} catch (err) {
console.error('复制失败', err);
copyBtn.textContent = '复制失败';
setTimeout(() => copyBtn.textContent = '复制代码段', 2000);
}
});
});
}
// 页面初次加载
window.addEventListener('load', addCustomCopyButton);
// 动态监听(掘金是 SPA,内容会异步加载)
const observer = new MutationObserver(addCustomCopyButton);
observer.observe(document.body, { childList: true, subtree: true });
})();
| 1 | // ==UserScript== |
| 2 | // @name 掘金复制代码段 |
| 3 | // @namespace https://docs.scriptcat.org/ |
| 4 | // @version 0.1.0 |
| 5 | // @description 免登录复制掘金代码片段 |
| 6 | // @author You |
| 7 | // @match https://juejin.cn/post/* |
| 8 | // @icon https://www.google.com/s2/favicons?sz=64&domain=juejin.cn |
| 9 | // @downloadURL https://gist.asfd.cn/jetsung/juejin/raw/HEAD/juejin.user.js |
| 10 | // @updateURL https://gist.asfd.cn/jetsung/juejin/raw/HEAD/juejin.user.js |
| 11 | // @grant none |
| 12 | // ==/UserScript== |
| 13 | |
| 14 | (function() { |
| 15 | 'use strict'; |
| 16 | |
| 17 | // 自定义按钮样式 |
| 18 | const customBtnStyle = { |
| 19 | display: 'inline-block', |
| 20 | padding: '2px 10px', |
| 21 | marginLeft: '8px', |
| 22 | fontSize: '13px', |
| 23 | color: '#fff', |
| 24 | backgroundColor: '#007fff', |
| 25 | borderRadius: '6px', |
| 26 | cursor: 'pointer', |
| 27 | userSelect: 'none', |
| 28 | transition: 'all 0.3s', |
| 29 | boxShadow: '0 2px 4px rgba(0,0,0,0.1)' |
| 30 | }; |
| 31 | |
| 32 | function addCustomCopyButton() { |
| 33 | document.querySelectorAll('.code-block-extension-header').forEach(header => { |
| 34 | const headerRight = header.querySelector('.code-block-extension-headerRight'); |
| 35 | if (!headerRight || headerRight.querySelector('.juejin-custom-copy-btn')) return; |
| 36 | |
| 37 | // 清空右侧所有原有按钮 |
| 38 | headerRight.innerHTML = ''; |
| 39 | |
| 40 | // 创建自定义按钮 |
| 41 | const copyBtn = document.createElement('div'); |
| 42 | copyBtn.className = 'juejin-custom-copy-btn'; |
| 43 | copyBtn.textContent = '复制代码段'; |
| 44 | Object.assign(copyBtn.style, customBtnStyle); |
| 45 | |
| 46 | // 悬停与成功效果 |
| 47 | copyBtn.addEventListener('mouseenter', () => copyBtn.style.backgroundColor = '#0066cc'); |
| 48 | copyBtn.addEventListener('mouseleave', () => { |
| 49 | if (copyBtn.textContent !== '复制成功') copyBtn.style.backgroundColor = '#007fff'; |
| 50 | }); |
| 51 | |
| 52 | headerRight.appendChild(copyBtn); |
| 53 | |
| 54 | // 复制逻辑(更稳健的纯文本提取) |
| 55 | copyBtn.addEventListener('click', async () => { |
| 56 | const codeContainer = header.parentElement.querySelector('pre code') || |
| 57 | header.nextElementSibling?.querySelector('code') || |
| 58 | header.parentElement.querySelector('code.hljs'); |
| 59 | |
| 60 | if (!codeContainer) { |
| 61 | copyBtn.textContent = '无代码'; |
| 62 | setTimeout(() => copyBtn.textContent = '复制代码段', 2000); |
| 63 | return; |
| 64 | } |
| 65 | |
| 66 | let pureCode = ''; |
| 67 | |
| 68 | // 优先尝试直接取 code 的纯文本(最干净) |
| 69 | if (codeContainer.textContent) { |
| 70 | pureCode = codeContainer.textContent.trim(); |
| 71 | } else { |
| 72 | // 备选:逐行提取 |
| 73 | const lines = Array.from(codeContainer.querySelectorAll('div, span, .code-block-extension-codeLine')) |
| 74 | .map(el => el.textContent || ''); |
| 75 | pureCode = lines.join('\n').trim(); |
| 76 | } |
| 77 | |
| 78 | // 去除可能的行号前缀(如果还有残留) |
| 79 | pureCode = pureCode.replace(/^\s*\d+\s*/gm, '').trim(); |
| 80 | |
| 81 | try { |
| 82 | await navigator.clipboard.writeText(pureCode); |
| 83 | copyBtn.textContent = '复制成功 ✓'; |
| 84 | copyBtn.style.backgroundColor = '#52c41a'; |
| 85 | setTimeout(() => { |
| 86 | copyBtn.textContent = '复制代码段'; |
| 87 | copyBtn.style.backgroundColor = '#007fff'; |
| 88 | }, 2000); |
| 89 | } catch (err) { |
| 90 | console.error('复制失败', err); |
| 91 | copyBtn.textContent = '复制失败'; |
| 92 | setTimeout(() => copyBtn.textContent = '复制代码段', 2000); |
| 93 | } |
| 94 | }); |
| 95 | }); |
| 96 | } |
| 97 | |
| 98 | // 页面初次加载 |
| 99 | window.addEventListener('load', addCustomCopyButton); |
| 100 | |
| 101 | // 动态监听(掘金是 SPA,内容会异步加载) |
| 102 | const observer = new MutationObserver(addCustomCopyButton); |
| 103 | observer.observe(document.body, { childList: true, subtree: true }); |
| 104 | })(); |