Greasy Fork

来自缓存

Greasy Fork is available in English.

Table 导出 CSV 右键菜单

为页面中的table元素添加右键菜单,支持导出为CSV文件

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Table 导出 CSV 右键菜单
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  为页面中的table元素添加右键菜单,支持导出为CSV文件
// @author       newbieking
// @match        *://*/*
// @grant        GM_registerMenuCommand
// @grant        GM_addStyle
// @license      MIT  
// ==/UserScript==   

(function() {
    'use strict';

    // 1. 定义全局变量,存储右键点击的table元素
    let targetTable = null;

    // 2. 添加右键菜单的样式,保证菜单美观且不被页面样式干扰
    GM_addStyle(`
        #newbieking-table-csv-menu {
            position: fixed;
            z-index: 999999;
            background: #fff;
            border: 1px solid #ccc;
            border-radius: 4px;
            box-shadow: 2px 2px 8px rgba(0,0,0,0.2);
            padding: 5px 0;
            display: none;
            min-width: 120px;
            font-size: 14px;
        }
        #newbieking-table-csv-menu li {
            list-style: none;
            padding: 6px 15px;
            cursor: pointer;
        }
        #newbieking-table-csv-menu li:hover {
            background-color: #f0f0f0;
        }
    `);

    // 3. 创建右键菜单DOM元素
    function createContextMenu() {
        // 避免重复创建菜单
        if (document.getElementById('newbieking-table-csv-menu')) return;

        const menu = document.createElement('ul');
        menu.id = 'newbieking-table-csv-menu';
        menu.innerHTML = `
            <li id="export-table-csv">导出为CSV文件</li>
        `;
        document.body.appendChild(menu);

        // 绑定菜单点击事件
        document.getElementById('export-table-csv').addEventListener('click', exportTableToCSV);

        // 点击页面其他区域关闭菜单
        document.addEventListener('click', (e) => {
            if (!menu.contains(e.target)) {
                menu.style.display = 'none';
            }
        });
    }

    // 4. 提取Table数据并转换为CSV格式
    function tableToCSV(table) {
        const csvRows = [];
        const rows = table.querySelectorAll('tr');

        // 遍历每一行
        for (const row of rows) {
            const csvCells = [];
            const cells = row.querySelectorAll('th, td');

            // 遍历每个单元格,处理特殊字符(逗号、换行、引号)
            for (const cell of cells) {
                // 获取单元格纯文本,去除多余空格和换行
                let cellText = cell.textContent.trim().replace(/\s+/g, ' ');
                // 处理CSV特殊字符:包含逗号/引号/换行时,用双引号包裹,内部双引号转义为两个
                if (cellText.includes(',') || cellText.includes('"') || cellText.includes('\n')) {
                    cellText = `"${cellText.replace(/"/g, '""')}"`;
                }
                csvCells.push(cellText);
            }

            // 单元格用逗号分隔,组成一行
            csvRows.push(csvCells.join(','));
        }

        // 行之间用换行分隔,生成完整CSV内容
        return csvRows.join('\n');
    }

    // 5. 导出CSV文件的核心函数
    function exportTableToCSV() {
        if (!targetTable) return;

        // 提取CSV数据
        const csvContent = tableToCSV(targetTable);
        // 创建Blob对象(UTF-8编码,解决中文乱码)
        const blob = new Blob(['\uFEFF' + csvContent], { type: 'text/csv;charset=utf-8;' });
        // 创建下载链接
        const url = URL.createObjectURL(blob);
        const link = document.createElement('a');
        // 设置文件名(用页面标题+时间戳,避免重复)
        const fileName = `${document.title.replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, '_')}_${new Date().getTime()}.csv`;
        link.setAttribute('href', url);
        link.setAttribute('download', fileName);
        link.style.display = 'none';
        document.body.appendChild(link);
        // 触发下载
        link.click();
        // 清理资源
        document.body.removeChild(link);
        URL.revokeObjectURL(url);
        // 关闭菜单
        document.getElementById('newbieking-table-csv-menu').style.display = 'none';
    }

    // 6. 监听页面右键事件,只在table上显示自定义菜单
    document.addEventListener('contextmenu', (e) => {
        // 判断右键目标是否是table,或table的子元素(td/th/tr)
        const table = e.target.closest('table');
        if (table) {
            // 阻止默认右键菜单
            e.preventDefault();
            // 记录当前目标table
            targetTable = table;
            // 创建菜单(首次执行)
            createContextMenu();
            // 显示菜单,定位到鼠标位置
            const menu = document.getElementById('newbieking-table-csv-menu');
            menu.style.display = 'block';
            menu.style.left = `${e.clientX}px`;
            menu.style.top = `${e.clientY}px`;

            // 处理菜单超出页面边界的情况(向右/向下超出时调整位置)
            const menuRect = menu.getBoundingClientRect();
            const windowWidth = window.innerWidth;
            const windowHeight = window.innerHeight;

            if (menuRect.right > windowWidth) {
                menu.style.left = `${e.clientX - menuRect.width}px`;
            }
            if (menuRect.bottom > windowHeight) {
                menu.style.top = `${e.clientY - menuRect.height}px`;
            }
        } else {
            // 非table区域,隐藏自定义菜单
            const menu = document.getElementById('newbieking-table-csv-menu');
            if (menu) menu.style.display = 'none';
        }
    });

})();