分享一个用于分享网页的小技巧
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);
}
})();

