本文于 2025年8月16日 10:00 更新,注意查看最新内容
一个经常使用的网站需要搭配手机一起使用,但是由于屏蔽了右键,导致Edge的QR码无法调用,于是用AI写了一个脚本,会在每个页面左边的正中间生成一个二维码图标,点击之后可以一键生成当前网页的二维码。
// ==UserScript== // @name 页面二维码生成器(完整缓存版) // @namespace http://tampermonkey.net/ // @version 1.4 // @description 生成当前页面二维码,带完善缓存机制确保图标正常显示 // @author 某知名AI // @match *://*/* // @grant GM_xmlhttpRequest // @grant GM_setValue // @grant GM_getValue // @grant GM_deleteValue // @connect cdnjs.cloudflare.com // @require https://cdn.jsdelivr.net/npm/qrcode@1.5.1/build/qrcode.min.js // ==/UserScript== (function() { 'use strict'; // 缓存配置 - 7天有效期 const CACHE_EXPIRY_DAYS = 7; const FONT_CACHE_KEY = 'qrcodeFontCache'; const FONT_CACHE_TIMESTAMP = 'qrcodeFontTimestamp'; // 所需字体文件URL const fontUrls = { woff2: 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/fonts/fontawesome-webfont.woff2?v=4.7.0', woff: 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/fonts/fontawesome-webfont.woff?v=4.7.0' }; // 检查缓存是否有效 function isCacheValid() { const timestamp = GM_getValue(FONT_CACHE_TIMESTAMP, 0); const now = new Date().getTime(); const expiryTime = CACHE_EXPIRY_DAYS * 24 * 60 * 60 * 1000; return timestamp + expiryTime > now; } // 从缓存加载字体 function loadFromCache() { const cachedFonts = GM_getValue(FONT_CACHE_KEY, null); if (cachedFonts) { injectFontStyles(cachedFonts); return true; } return false; } // 下载字体并缓存 function downloadAndCacheFonts() { // 优先尝试woff2格式,兼容性更好 fetchFont(fontUrls.woff2, 'woff2') .catch(() => { // 如果woff2失败,尝试woff格式 return fetchFont(fontUrls.woff, 'woff'); }) .then(({data, format}) => { const fontData = {data, format}; // 存储到缓存 GM_setValue(FONT_CACHE_KEY, fontData); GM_setValue(FONT_CACHE_TIMESTAMP, new Date().getTime()); injectFontStyles(fontData); }) .catch(() => { // 所有字体加载失败时使用基础样式 fallback injectFallbackStyles(); }); } // 下载字体文件 function fetchFont(url, format) { return new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: 'GET', url: url, responseType: 'arraybuffer', onload: function(response) { if (response.status === 200 && response.response) { // 转换为base64 const base64Data = btoa( new Uint8Array(response.response).reduce( (data, byte) => data + String.fromCharCode(byte), '' ) ); resolve({data: base64Data, format}); } else { reject(new Error(`Failed to load font: ${response.status}`)); } }, onerror: function() { reject(new Error('Network error while loading font')); }, ontimeout: function() { reject(new Error('Font loading timed out')); } }); }); } // 注入字体样式 function injectFontStyles(fontData) { const style = document.createElement('style'); style.textContent = ` @font-face { font-family: 'FontAwesome'; src: url('data:application/font-${fontData.format};base64,${fontData.data}') format('${fontData.format}'); font-weight: normal; font-style: normal; } .fa { display: inline-block; font: normal normal normal 14px/1 FontAwesome; font-size: inherit; text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } .fa-qrcode:before { content: "\\f029"; } .fa-times:before { content: "\\f00d"; } `; document.head.appendChild(style); } // 字体加载失败时的 fallback 样式 function injectFallbackStyles() { const style = document.createElement('style'); style.textContent = ` .fa-qrcode:before { content: "🔳"; } .fa-times:before { content: "✕"; } `; document.head.appendChild(style); } // 创建UI元素 function createUI() { // 创建按钮容器 const buttonContainer = document.createElement('div'); buttonContainer.style.position = 'fixed'; buttonContainer.style.left = '10px'; buttonContainer.style.top = '50%'; buttonContainer.style.transform = 'translateY(-50%)'; buttonContainer.style.zIndex = '9999'; buttonContainer.style.display = 'flex'; buttonContainer.style.flexDirection = 'column'; buttonContainer.style.alignItems = 'center'; // 创建二维码按钮 const qrButton = document.createElement('button'); qrButton.innerHTML = '<i class="fa fa-qrcode"></i>'; // 创建关闭按钮(默认隐藏) const hideButton = document.createElement('button'); hideButton.innerHTML = '<i class="fa fa-times"></i>'; hideButton.style.position = 'absolute'; hideButton.style.top = '-10px'; hideButton.style.right = '-10px'; hideButton.style.width = '24px'; hideButton.style.height = '24px'; hideButton.style.borderRadius = '50%'; hideButton.style.backgroundColor = '#f44336'; hideButton.style.color = 'white'; hideButton.style.border = 'none'; hideButton.style.cursor = 'pointer'; hideButton.style.boxShadow = '0 1px 3px rgba(0,0,0,0.2)'; hideButton.style.display = 'none'; // 默认隐藏 hideButton.style.alignItems = 'center'; hideButton.style.justifyContent = 'center'; hideButton.style.fontSize = '12px'; hideButton.title = '彻底隐藏二维码按钮(刷新页面可恢复)'; // 二维码按钮样式 qrButton.style.width = '40px'; qrButton.style.height = '40px'; qrButton.style.borderRadius = '8px'; qrButton.style.backgroundColor = 'rgba(255, 255, 255, 0.8)'; qrButton.style.color = '#333'; qrButton.style.border = '1px solid #ddd'; qrButton.style.cursor = 'pointer'; qrButton.style.boxShadow = '0 2px 5px rgba(0,0,0,0.1)'; qrButton.style.transition = 'all 0.3s ease'; qrButton.style.display = 'flex'; qrButton.style.alignItems = 'center'; qrButton.style.justifyContent = 'center'; qrButton.style.fontSize = '18px'; qrButton.title = '生成当前页面二维码'; // 按钮容器悬停效果 buttonContainer.addEventListener('mouseover', () => { qrButton.style.width = '50px'; qrButton.style.backgroundColor = 'white'; qrButton.style.boxShadow = '0 3px 8px rgba(0,0,0,0.2)'; hideButton.style.display = 'flex'; }); buttonContainer.addEventListener('mouseout', () => { qrButton.style.width = '40px'; qrButton.style.backgroundColor = 'rgba(255, 255, 255, 0.8)'; qrButton.style.boxShadow = '0 2px 5px rgba(0,0,0,0.1)'; hideButton.style.display = 'none'; }); // 弹窗元素(延迟创建) let qrModal, qrContainer, closeButton, urlText; function initModal() { if (qrModal) return; // 创建二维码弹窗容器 qrModal = document.createElement('div'); qrModal.style.position = 'fixed'; qrModal.style.top = '0'; qrModal.style.left = '0'; qrModal.style.width = '100%'; qrModal.style.height = '100%'; qrModal.style.backgroundColor = 'rgba(0,0,0,0.7)'; qrModal.style.display = 'none'; qrModal.style.justifyContent = 'center'; qrModal.style.alignItems = 'center'; qrModal.style.zIndex = '10000'; qrModal.style.flexDirection = 'column'; qrModal.style.backdropFilter = 'blur(3px)'; // 创建二维码图片容器 qrContainer = document.createElement('div'); qrContainer.style.backgroundColor = 'white'; qrContainer.style.padding = '20px'; qrContainer.style.borderRadius = '10px'; qrContainer.style.boxShadow = '0 0 20px rgba(0,0,0,0.5)'; qrContainer.style.textAlign = 'center'; qrContainer.style.maxWidth = '90%'; qrContainer.style.transform = 'scale(0.95)'; qrContainer.style.transition = 'transform 0.3s ease'; // 创建关闭按钮 closeButton = document.createElement('button'); closeButton.innerHTML = '<i class="fa fa-times"></i> 关闭'; closeButton.style.marginTop = '20px'; closeButton.style.padding = '8px 16px'; closeButton.style.backgroundColor = '#666'; closeButton.style.color = 'white'; closeButton.style.border = 'none'; closeButton.style.borderRadius = '5px'; closeButton.style.cursor = 'pointer'; closeButton.style.fontSize = '14px'; closeButton.style.transition = 'background-color 0.2s'; closeButton.addEventListener('mouseover', () => { closeButton.style.backgroundColor = '#333'; }); closeButton.addEventListener('mouseout', () => { closeButton.style.backgroundColor = '#666'; }); // 页面URL文本显示 urlText = document.createElement('p'); urlText.style.wordBreak = 'break-all'; urlText.style.maxWidth = '300px'; urlText.style.marginTop = '15px'; urlText.style.fontSize = '14px'; urlText.style.color = '#555'; // 组装弹窗 qrContainer.appendChild(urlText); qrModal.appendChild(qrContainer); qrModal.appendChild(closeButton); document.body.appendChild(qrModal); // 弹窗事件监听 closeButton.addEventListener('click', () => { qrModal.style.display = 'none'; }); qrModal.addEventListener('click', (e) => { if (e.target === qrModal) { qrModal.style.display = 'none'; } }); document.addEventListener('keydown', (e) => { if (e.key === 'Escape' && qrModal.style.display === 'flex') { qrModal.style.display = 'none'; } }); } // 生成二维码函数 function generateQRCode() { initModal(); // 首次点击时初始化弹窗 // 清空之前的二维码 while (qrContainer.firstChild) { if (qrContainer.firstChild.tagName === 'IMG' || qrContainer.firstChild.tagName === 'CANVAS') { qrContainer.removeChild(qrContainer.firstChild); } else { break; } } // 重置容器缩放 qrContainer.style.transform = 'scale(0.95)'; // 获取当前页面URL const currentUrl = window.location.href; urlText.textContent = currentUrl; // 生成二维码 QRCode.toCanvas(currentUrl, { width: 300, margin: 1 }, function (error, canvas) { if (error) { console.error(error); alert('生成二维码失败: ' + error.message); return; } qrContainer.insertBefore(canvas, qrContainer.firstChild); }); // 显示弹窗 qrModal.style.display = 'flex'; } // 彻底隐藏二维码按钮 function hideQRButtonCompletely() { if (buttonContainer.parentNode === document.body) { document.body.removeChild(buttonContainer); } } // 绑定事件 qrButton.addEventListener('click', generateQRCode); hideButton.addEventListener('click', hideQRButtonCompletely); // 添加到页面 buttonContainer.appendChild(qrButton); buttonContainer.appendChild(hideButton); document.body.appendChild(buttonContainer); } // 初始化流程 - 优先使用缓存 if (isCacheValid() && loadFromCache()) { // 缓存有效且加载成功,创建UI createUI(); } else { // 缓存无效或加载失败,重新下载 downloadAndCacheFonts(); // 无论字体加载结果如何,都创建UI(确保基本功能可用) createUI(); } })();
Comments | 2 条评论
可以在每一个页面加一个,这样手机可以直接扫码浏览
这个不错