看了两位大佬的书签快捷方式,我直接合二为一:快捷复制dom文本和标题+url

分享一个用于分享网页的小技巧
memo 分享个实用小函数(书签):鼠标选择提取网页文本

感谢以上两位大佬!以下是合二为一的篡改猴脚本插件:支持快捷复制页面dom文本和复制分享标题+url


篡改猴源码如下:

// ==UserScript==
// @name         快捷分享页面内容
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  一个方便用户快捷分享页面内容的浏览器插件
// @author       vitor0519
// @match        *://*/*
// @noframes
// @grant        GM_setClipboard
// @grant        GM_notification
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // 创建分享按钮
    function createShareButton() {
        const shareButton = document.createElement('div');
        shareButton.id = 'quick-share-button';
        shareButton.innerHTML = `
            <div id="share-button-main" style="
                position: fixed;
                bottom: 20px;
                right: 20px;
                width: 60px;
                height: 60px;
                background-color: #4285f4;
                border-radius: 50%;
                display: flex;
                align-items: center;
                justify-content: center;
                cursor: pointer;
                box-shadow: 0 2px 10px rgba(0,0,0,0.3);
                z-index: 9999;
                transition: all 0.3s ease;
            ">
                <svg width="30" height="30" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                    <circle cx="18" cy="5" r="3"></circle>
                    <circle cx="6" cy="12" r="3"></circle>
                    <circle cx="18" cy="19" r="3"></circle>
                    <line x1="8.59" y1="13.51" x2="15.42" y2="17.49"></line>
                    <line x1="15.41" y1="6.51" x2="8.59" y2="10.49"></line>
                </svg>
            </div>
            <div id="share-button-indicator" style="
                position: fixed;
                bottom: 20px;
                right: 10px;
                width: 10px;
                height: 40px;
                background-color: #4285f4;
                border-radius: 5px 0 0 5px;
                display: none;
                cursor: pointer;
                box-shadow: -2px 0 5px rgba(0,0,0,0.2);
                z-index: 9999;
                transition: all 0.3s ease;
            "></div>
        `;

        const buttonMain = shareButton.querySelector('#share-button-main');
        const buttonIndicator = shareButton.querySelector('#share-button-indicator');

        // 添加悬停效果
        buttonMain.addEventListener('mouseenter', function() {
            if (!this.dataset.hidden) {
                this.style.transform = 'scale(1.1)';
                this.style.backgroundColor = '#3367d6';
            }
        });

        buttonMain.addEventListener('mouseleave', function() {
            if (!this.dataset.hidden) {
                this.style.transform = 'scale(1)';
                this.style.backgroundColor = '#4285f4';
            }
        });

        // 指示器悬停效果
        buttonIndicator.addEventListener('mouseenter', function() {
            this.style.width = '15px';
            this.style.backgroundColor = '#3367d6';
        });

        buttonIndicator.addEventListener('mouseleave', function() {
            this.style.width = '10px';
            this.style.backgroundColor = '#4285f4';
        });

        // 点击事件 - 显示菜单
        buttonMain.addEventListener('click', function(e) {
            if (e.detail === 1) { // 单击
                showShareMenu();
            }
        });

        // 双击事件 - 切换隐藏/显示
        buttonMain.addEventListener('dblclick', function() {
            toggleButtonVisibility(this, buttonIndicator);
        });

        // 指示器点击事件 - 显示按钮
        buttonIndicator.addEventListener('click', function() {
            toggleButtonVisibility(buttonMain, this);
        });

        document.body.appendChild(shareButton);
    }

    // 切换按钮可见性
    function toggleButtonVisibility(buttonMain, buttonIndicator) {
        if (buttonMain.dataset.hidden === 'true') {
            // 显示按钮
            buttonMain.style.right = '20px';
            buttonMain.style.transform = 'scale(1)';
            buttonMain.dataset.hidden = 'false';
            buttonIndicator.style.display = 'none';
        } else {
            // 隐藏按钮
            buttonMain.style.right = '-40px';
            buttonMain.style.transform = 'scale(0.8)';
            buttonMain.dataset.hidden = 'true';
            buttonIndicator.style.display = 'block';
        }
    }

    // 显示分享菜单
    function showShareMenu() {
        // 移除已存在的菜单
        const existingMenu = document.getElementById('quick-share-menu');
        if (existingMenu) {
            existingMenu.remove();
            return;
        }

        // 获取按钮状态
        const buttonMain = document.querySelector('#share-button-main');
        const isHidden = buttonMain.dataset.hidden === 'true';
        const menuRight = isHidden ? '50px' : '20px';

        const shareMenu = document.createElement('div');
        shareMenu.id = 'quick-share-menu';
        shareMenu.innerHTML = `
            <div style="
                position: fixed;
                bottom: 90px;
                right: ${menuRight};
                background-color: #2c3e50;
                border-radius: 8px;
                box-shadow: 0 4px 20px rgba(0,0,0,0.4);
                z-index: 10000;
                width: 200px;
                padding: 12px;
                font-family: Arial, sans-serif;
            ">
                <div style="
                    font-size: 16px;
                    font-weight: bold;
                    margin-bottom: 12px;
                    padding-bottom: 10px;
                    border-bottom: 1px solid #34495e;
                    color: #ecf0f1;
                ">分享此页面</div>
                <div class="share-option" data-action="copy-both" style="
                    padding: 12px;
                    cursor: pointer;
                    border-radius: 6px;
                    display: flex;
                    align-items: center;
                    margin-bottom: 8px;
                    color: #ecf0f1;
                    transition: background-color 0.2s;
                ">
                    <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#ecf0f1" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right: 12px;">
                        <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
                        <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
                    </svg>
                    复制标题和链接
                </div>
                <div class="share-option" data-action="copy-dom-text" style="
                    padding: 12px;
                    cursor: pointer;
                    border-radius: 6px;
                    display: flex;
                    align-items: center;
                    margin-bottom: 8px;
                    color: #ecf0f1;
                    transition: background-color 0.2s;
                ">
                    <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#ecf0f1" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right: 12px;">
                        <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
                        <polyline points="14 2 14 8 20 8"></polyline>
                        <line x1="16" y1="13" x2="8" y2="13"></line>
                        <line x1="16" y1="17" x2="8" y2="17"></line>
                        <polyline points="10 9 9 9 8 9"></polyline>
                    </svg>
                    复制页面文本
                </div>
                <div class="share-option" data-action="share-weibo" style="
                    padding: 12px;
                    cursor: pointer;
                    border-radius: 6px;
                    display: flex;
                    align-items: center;
                    color: #ecf0f1;
                    transition: background-color 0.2s;
                ">
                    <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#ecf0f1" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right: 12px;">
                        <path d="M22 4s-.7 2.1-2 3.4c1.6 10-9.4 17.3-18 11.6 2.2.1 4.4-.6 6-2C3 15.5.5 9.6 3 5c2.2 2.6 5.6 4.1 9 4-.9-4.2 4-6.6 7-3.8 1.1 0 3-1.2 3-1.2z"></path>
                    </svg>
                    分享到微博
                </div>
            </div>
        `;

        // 添加选项悬停效果
        const options = shareMenu.querySelectorAll('.share-option');
        options.forEach(option => {
            option.addEventListener('mouseenter', function() {
                this.style.backgroundColor = '#34495e';
            });

            option.addEventListener('mouseleave', function() {
                this.style.backgroundColor = 'transparent';
            });

            // 添加点击事件
            option.addEventListener('click', function() {
                handleShareAction(this.dataset.action);
                shareMenu.remove();
            });
        });

        document.body.appendChild(shareMenu);

        // 点击其他地方关闭菜单
        setTimeout(() => {
            document.addEventListener('click', function closeMenu(e) {
                if (!shareMenu.contains(e.target) && e.target.id !== 'quick-share-button') {
                    shareMenu.remove();
                    document.removeEventListener('click', closeMenu);
                }
            });
        }, 100);
    }

    // 处理分享动作
    function handleShareAction(action) {
        const title = document.title;
        const url = window.location.href;
        const selectedText = window.getSelection().toString().trim();

        switch (action) {
            case 'copy-both':
                GM_setClipboard(`${title}\n${url}`);
                showNotification('标题和链接已复制到剪贴板');
                break;

            case 'copy-dom-text':
                activateDOMTextSelector();
                break;

            case 'share-weibo':
                const weiboText = selectedText ? `${title} - ${selectedText}` : title;
                window.open(`https://service.weibo.com/share/share.php?title=${encodeURIComponent(weiboText)}&url=${encodeURIComponent(url)}`, '_blank');
                break;

        }
    }

    // 显示通知
    function showNotification(message) {
        if (typeof GM_notification !== 'undefined') {
            GM_notification({
                title: '快捷分享',
                text: message,
                timeout: 3000
            });
        } else {
            // 如果 GM_notification 不可用,使用自定义通知
            const notification = document.createElement('div');
            notification.style.cssText = `
                position: fixed;
                top: 20px;
                right: 20px;
                background-color: #333;
                color: white;
                padding: 15px 20px;
                border-radius: 4px;
                box-shadow: 0 2px 10px rgba(0,0,0,0.2);
                z-index: 10001;
                font-family: Arial, sans-serif;
                font-size: 14px;
            `;
            notification.textContent = message;
            document.body.appendChild(notification);

            setTimeout(() => {
                notification.style.opacity = '0';
                notification.style.transition = 'opacity 0.5s';
                setTimeout(() => notification.remove(), 500);
            }, 2500);
        }
    }

    // DOM文本选择功能
    function activateDOMTextSelector() {
        // 关闭分享菜单
        const existingMenu = document.getElementById('quick-share-menu');
        if (existingMenu) {
            existingMenu.remove();
        }

        const indent = "  ";
        let highlightBox = null;
        let notificationBox = null;

        // 提取节点文本内容
        function extractNodeText(node, depth = 0) {
            let text = "";

            if (node.nodeType === Node.ELEMENT_NODE) {
                const styles = window.getComputedStyle(node);
                if (styles.display === 'none' || styles.visibility === 'hidden') {
                    return "";
                }
                if (["SCRIPT", "STYLE", "NOSCRIPT"].includes(node.tagName.toUpperCase())) {
                    return "";
                }
            }

            if (node.nodeType === Node.TEXT_NODE) {
                const content = node.textContent.trim();
                return content ? content : "";
            }

            let childText = "";
            if (node.childNodes && node.childNodes.length > 0) {
                node.childNodes.forEach(child => {
                    childText += extractNodeText(child, depth + 1);
                });
            }

            const tagName = node.tagName ? node.tagName.toUpperCase() : "";
            if (tagName === "A" && node.href) {
                text += `[${childText.trim()}](${node.href})`;
            } else if (isBlockElement(node) && childText.trim()) {
                text += "\n" + indent.repeat(depth) + childText.trim() + "\n";
            } else if (tagName === "LI") {
                text += "\n" + indent.repeat(depth) + "- " + childText.trim();
            } else {
                text += childText;
            }

            return text.replace(/\n\s*\n/g, "\n");
        }

        // 判断是否为块级元素
        function isBlockElement(element) {
            if (!element || element.nodeType !== Node.ELEMENT_NODE) return false;
            const display = window.getComputedStyle(element).display;
            return ["block", "flex", "grid", "list-item", "table"].includes(display);
        }

        // 创建高亮框
        function createHighlightBox() {
            highlightBox = document.createElement("div");
            highlightBox.style.cssText = "position:absolute;box-sizing:border-box;border:2px solid #007bff;background:rgba(0,123,255,.1);z-index:999999;pointer-events:none;transition:all .1s ease-in-out";

            notificationBox = document.createElement("div");
            notificationBox.style.cssText = "position:fixed;bottom:20px;left:50%;transform:translateX(-50%);background-color:#333;color:white;padding:10px 20px;border-radius:5px;z-index:1000000;font-family:sans-serif;font-size:14px";
            notificationBox.textContent = "移动鼠标选择元素,单击复制,按 ESC 取消";

            document.body.appendChild(highlightBox);
            document.body.appendChild(notificationBox);
        }

        // 清理选择器
        function cleanupSelector() {
            if (highlightBox) highlightBox.remove();
            if (notificationBox) notificationBox.remove();
            document.removeEventListener("click", handleClick, true);
            document.removeEventListener("mouseover", handleMouseOver, true);
            document.removeEventListener("keydown", handleKeyDown, true);
        }

        // 更新高亮框位置
        function updateHighlightBox(element) {
            if (!element || !highlightBox) return;

            const rect = element.getBoundingClientRect();
            highlightBox.style.top = `${rect.top + window.scrollY}px`;
            highlightBox.style.left = `${rect.left + window.scrollX}px`;
            highlightBox.style.width = `${rect.width}px`;
            highlightBox.style.height = `${rect.height}px`;
        }

        // 处理点击事件
        function handleClick(event) {
            event.preventDefault();
            event.stopPropagation();

            const target = event.target;
            const text = extractNodeText(target, 0).trim();

            if (text) {
                navigator.clipboard.writeText(text).then(() => {
                    if (highlightBox) highlightBox.style.display = "none";
                    notificationBox.textContent = "✅ 已复制到剪贴板!";
                    setTimeout(cleanupSelector, 1200);
                }).catch(err => {
                    notificationBox.textContent = `❌ 复制失败: ${err}`;
                    setTimeout(cleanupSelector, 2000);
                });
            } else {
                notificationBox.textContent = "❌ 未找到可复制的文本内容。";
                setTimeout(cleanupSelector, 2000);
            }
        }

        // 处理鼠标移动事件
        function handleMouseOver(event) {
            updateHighlightBox(event.target);
        }

        // 处理键盘事件
        function handleKeyDown(event) {
            if (event.key === "Escape") {
                cleanupSelector();
            }
        }

        // 激活选择器
        createHighlightBox();
        document.addEventListener("click", handleClick, true);
        document.addEventListener("mouseover", handleMouseOver, true);
        document.addEventListener("keydown", handleKeyDown, true);
    }

    // 初始化
    function init() {
        // 检查是否在iframe中
        if (window.top !== window.self) {
            return; // 如果在iframe中,不初始化插件
        }
        createShareButton();
    }

    // 等待页面加载完成
    if (document.readyState === 'complete' || document.readyState === 'interactive') {
        init();
    } else {
        document.addEventListener('DOMContentLoaded', init);
    }
})();
8 个赞

感谢大佬!

感谢大佬!

感谢大佬 :+1: :+1:

感觉这个功能加到简约翻译上就很好

感谢各位,重回3级 :face_with_peeking_eye:

翻译还是沉浸式插件好

感谢分享

虽然功能上沉浸式是最好,但是不用


闲着无聊,优化了一下,有需要滴滴