您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
适用于任意网站,快速复制表格为纯文本、HTML、图片
当前为
// ==UserScript== // @name table-copier // @namespace http://tampermonkey.net/ // @version 0.3 // @description 适用于任意网站,快速复制表格为纯文本、HTML、图片 // @match *://*/* // @require https://cdn.staticfile.org/html2canvas/1.4.1/html2canvas.min.js // @grant none // @run-at document-idle // @license GPL-3.0-only // @create 2023-06-27 // ==/UserScript== (function() { "use strict"; const SCRIPTS = [ ["html2canvas", "https://cdn.staticfile.org/html2canvas/1.4.1/html2canvas.min.js"] ]; const BTN = `<button class="never-gonna-give-you-up" style="width: 70px; height: 30px;" onclick="copy_table(this)">复制表格</button>`; const COPY_GAP = 500; const BOOT_DELAY = 2000; /** * 元素选择器 * @param {string} selector * @returns {Array<HTMLElement>} */ function $(selector) { const self = this?.querySelectorAll ? this : document; return [...self.querySelectorAll(selector)]; } /** * 异步等待delay毫秒 * @param {number} delay * @returns */ function sleep(delay) { return new Promise(resolve => setTimeout(resolve, delay)); } /** * 加载CDN脚本 * @param {string} url */ async function load_script(url) { try { const code = await (await fetch(url)).text(); Function(code)(); } catch(e) { return new Promise(resolve => { console.error(e); // 嵌入<script>方式 const script = document.createElement("script"); script.src = url; script.onload = resolve; document.body.appendChild(script); }); } } async function until_scripts_loaded() { return gather(SCRIPTS.map( // kv: [prop, url] kv => (async () => { if (window[kv[0]]) return; await load_script(kv[1]); })() )); } /** * 等待全部任务落定后返回值的列表 * @param {Iterable<Promise>} tasks * @returns {Promise<Array>} values */ async function gather(tasks) { const results = await Promise.allSettled(tasks); const filtered = []; for (const result of results) { if (result.value) { filtered.push(result.value); } } return filtered; } /** * 递归的修正表内元素 * @param {HTMLElement} elem */ function adjust_table(elem) { for (const child of elem.children) { adjust_table(child); for (const attr of child.attributes) { // 链接补全 const name = attr.name; if (["src", "href"].includes(name)) { child.setAttribute(name, child[name]); } } } } /** * @param {Blob} blob * @returns {ClipboardItem} */ function blob_to_item(blob) { return new ClipboardItem({ [blob.type]: blob }); } /** * canvas转blob * @param {HTMLCanvasElement} canvas * @param {string} type * @returns {Promise<Blob>} */ function canvas_to_blob(canvas) { return new Promise( resolve => canvas.toBlob(resolve, "image/png") ); } /** * 表格转tsv字符串 * @param {HTMLTableElement} table */ function table_to_tsv(table) { return [...table.rows].map( row => [...row.cells].map( cell => cell .textContent .replace(/\n/g, "") .replace(/\t/g, " ") .trim() ).join("\t") ).join("\n"); } /** * @param {HTMLTableElement} table * @returns {Promise<Blob>} */ async function table_to_text_blob(table) { console.log("table to text"); // table 转 tsv 格式文本 const text = table_to_tsv(table); console.log(text); return new Blob([text], { type: "text/plain" }); } /** * @param {HTMLTableElement} table * @returns {Promise<Blob>} */ async function table_to_html_blob(table) { console.log("table to html"); const _table = table.cloneNode(true); adjust_table(_table); return new Blob([_table.outerHTML], { type: "text/html" }); } /** * @param {HTMLTableElement} table * @returns {Promise<Blob>} */ async function table_to_image_blob(table) { console.log("table to image"); let canvas; try { canvas = await window.html2canvas(table); } catch(e) { console.error(e); } console.log("canvas:", canvas); if (!canvas) return; return canvas_to_blob(canvas); } /** * 使用过时的 execCommand 复制文本 * @param {string} text * @returns {Promise<string>} */ async function old_copy(text) { return new Promise(resolve => { document.oncopy = event => { event.clipboardData.setData("text/plain", text); event.preventDefault(); resolve(); }; document.execCommand("copy"); }); } /** * @param {Blob} blob * @returns {Promise<void>} */ function copy(blob) { const item = blob_to_item(blob); return navigator.clipboard.write([item]); } /** * @param {HTMLTableElement} table * @returns {Promise<void>} */ async function copy_table_as_multi_types(table) { const converts = [ table_to_text_blob, table_to_html_blob, table_to_image_blob, ]; const blobs = await gather(converts.map( convert => convert(table) )); try { const last_blob = blobs.pop(); for (const blob of blobs) { await copy(blob); await sleep(COPY_GAP); } await copy(last_blob); alert("复制成功!"); } catch(e) { console.error(e); alert("复制失败!"); } } /** * @param {HTMLTableElement} table * @returns {Promise<void>} */ async function copy_table_as_text(table) { try { await old_copy(table_to_tsv(table)); alert("复制成功!"); } catch(e) { console.error(e); alert("复制失败!"); } } /** * 复制表格到剪贴板 * @param {HTMLButtonElement} btn */ async function copy_table(btn) { const table = btn.closest("table"); if (!table) { alert("出错了:按钮外部没有表格"); return; } // 移除按钮 $(".never-gonna-give-you-up").forEach( btn => btn.remove() ); // 复制表格 if (!navigator.clipboard) { await copy_table_as_text(table); } else { await copy_table_as_multi_types(table); } // 增加按钮 add_btns(); } function add_btns() { for (const table of $("table")) { // 跳过隐藏的表格 if (!table.getClientRects()[0]) continue; table.insertAdjacentHTML("afterbegin", BTN); } } async function main() { try { await until_scripts_loaded(); } catch(e) { console.error(e); } window.copy_table = copy_table; add_btns(); // 递归的注入自身到iframe $("iframe").forEach(iframe => { try { iframe.contentWindow.eval(main.toString()); } catch(e) {} }); }; setTimeout(main, BOOT_DELAY); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址