A-A+
选中即弹出复制按钮的tampermonkey(油猴)脚本

【注意:此文章为博主原创文章!转载需注意,请带原文链接,至少也要是txt格式!】
使用此脚本,选中任何网站的内容,在内容旁都会弹出复制按钮,点击即可复制选中的内容。(部分百度等不可以。)
// ==UserScript==
// @name 精准选区复制按钮
// @namespace http://tampermonkey.net/
// @version 1.3
// @description 在选区结尾精准弹出复制按钮,兼容输入框和页面选区
// @author GPT
// @match *://*/*
// @grant GM_setClipboard
// @run-at document-end
// ==/UserScript==
(function() {
'use strict';
// 复制功能
function copyTextToClipboard(text) {
if (typeof GM_setClipboard === "function") {
GM_setClipboard(text, "text");
} else if (navigator.clipboard) {
navigator.clipboard.writeText(text);
} else {
const textarea = document.createElement('textarea');
textarea.value = text;
document.body.appendChild(textarea);
textarea.select();
document.execCommand('copy');
document.body.removeChild(textarea);
}
}
// 复制按钮生成
function createCopyBtn() {
const btn = document.createElement('div');
btn.innerHTML = `
<span style="
font-size:15px;
user-select:none;
cursor:pointer;
color:#fff;
background:rgba(33,36,50,0.9);
border-radius:5px;
padding:4px 8px;
box-shadow:0 2px 8px #0002;
display:flex;
align-items:center;
">
<svg width="18" height="18" style="margin-right:3px;" viewBox="0 0 24 24" fill="none"><rect x="9" y="9" width="13" height="13" rx="2" fill="#fff" fill-opacity="0.3"/><rect x="2" y="2" width="13" height="13" rx="2" fill="#fff"/></svg>
复制
</span>
`;
btn.style.position = 'fixed';
btn.style.zIndex = '999999';
btn.style.display = 'none';
btn.style.pointerEvents = 'auto';
btn.className = 'tm-copy-selection-btn-gpt';
document.body.appendChild(btn);
return btn;
}
const copyBtn = createCopyBtn();
let hideTimer = null;
function showCopyBtn(text, clientX, clientY) {
copyBtn.style.left = `${clientX + 6}px`;
copyBtn.style.top = `${clientY + 8}px`;
copyBtn.style.display = 'block';
copyBtn.children[0].innerHTML = `
<svg width="18" height="18" style="margin-right:3px;" viewBox="0 0 24 24" fill="none"><rect x="9" y="9" width="13" height="13" rx="2" fill="#fff" fill-opacity="0.3"/><rect x="2" y="2" width="13" height="13" rx="2" fill="#fff"/></svg>
复制`;
copyBtn.onclick = function(e) {
e.stopPropagation();
copyTextToClipboard(text);
copyBtn.children[0].innerText = "✔ 已复制";
setTimeout(hideCopyBtn, 1000);
};
clearTimeout(hideTimer);
hideTimer = setTimeout(hideCopyBtn, 10000); // 注释或删除这一行 复制按钮就不回消失
}
function hideCopyBtn() {
copyBtn.style.display = 'none';
}
// 判断是否是在输入框选区
function getInputSelectionPosition(inputEl) {
// 当前文本选区结束位置
const start = inputEl.selectionEnd;
// 创建一个临时 span 计算实际位置
const value = inputEl.value;
// 创建 shadow span
const div = document.createElement('div');
const style = getComputedStyle(inputEl);
for(let p of ['fontSize','fontFamily','fontWeight','letterSpacing','paddingLeft','paddingTop','paddingRight','paddingBottom','borderLeftWidth','borderTopWidth','borderRightWidth','borderBottomWidth','whiteSpace']){
div.style = style;
}
div.style.position = 'absolute';
div.style.visibility = 'hidden';
div.style.whiteSpace = 'pre-wrap';
div.style.wordBreak = 'break-word';
div.style.left = '-9999px';
div.textContent = value.substring(0, start);
document.body.appendChild(div);
// 计算 span 的位置
const rect = div.getBoundingClientRect();
const inputRect = inputEl.getBoundingClientRect();
let x = inputRect.left + rect.width;
let y = inputRect.top + rect.height;
document.body.removeChild(div);
// 修正超出
x = Math.min(x, inputRect.right - 20);
y = Math.min(y, inputRect.bottom - 20);
return {clientX: x, clientY: y};
}
// 处理mouseup事件
document.addEventListener('mouseup', function(e) {
setTimeout(() => {
let sel = window.getSelection();
// 普通页面选区
if(sel && sel.toString().trim()) {
let range = sel.getRangeAt(0);
// 对于嵌入式容器的选区,要能聚焦实际内容最后
let rect = range.getClientRects();
let visibleRect = rect[rect.length - 1] || range.getBoundingClientRect();
if(visibleRect.width === 0 && visibleRect.height === 0) {
hideCopyBtn();
return;
}
// 计算相对于视口的位置
let clientX = visibleRect.right;
let clientY = visibleRect.bottom;
showCopyBtn(sel.toString(), clientX, clientY);
return;
}
// 如果是在输入框或textarea选中内容
let activeEl = document.activeElement;
if (activeEl && (activeEl.tagName === 'TEXTAREA' || (activeEl.tagName === 'INPUT' && /text|search|url|email|password/.test(activeEl.type)))) {
const s = activeEl.selectionStart, e = activeEl.selectionEnd;
if (s !== e) {
// 获取选区位置
let pos = getInputSelectionPosition(activeEl);
showCopyBtn(activeEl.value.substring(s,e), pos.clientX, pos.clientY);
return;
}
}
hideCopyBtn();
}, 15);
});
// 隐藏按钮:点页面/ESC
document.addEventListener('mousedown', function(e){
if (!copyBtn.contains(e.target)) {
hideCopyBtn();
}
});
document.addEventListener('keydown', function(e){
if(e.key === "Escape"){ hideCopyBtn(); }
});
document.addEventListener('scroll', hideCopyBtn, true);
window.addEventListener('resize', hideCopyBtn, true);
// 强制支持 ctrl+C
document.addEventListener('copy', function(e){
let sel = window.getSelection();
if(sel && sel.toString() && e.clipboardData){
e.clipboardData.setData('text/plain', sel.toString());
e.preventDefault();
}
// 针对输入textarea
let activeEl = document.activeElement;
if (activeEl && (activeEl.tagName === 'TEXTAREA' || (activeEl.tagName === 'INPUT' && /text|search|url|email|password/.test(activeEl.type)))) {
const s = activeEl.selectionStart, ee = activeEl.selectionEnd;
if (s !== ee) {
e.clipboardData.setData('text/plain', activeEl.value.substring(s, ee));
e.preventDefault();
}
}
}, true);
})();
布施恩德可便相知重
微信扫一扫打赏
支付宝扫一扫打赏