// ==UserScript== // @name 常用邮箱/手机号/密码 一键填写助手(可隐藏+快捷键) // @namespace https://example.com // @version 0.7.3 // @description 支持邮箱、手机号、密码快速填写;Delete 键 切换面板显隐;导出使用 clipboard API + fallback // @author You // @match *://*/* // @grant GM_registerMenuCommand // @grant GM_setValue // @grant GM_getValue // @grant GM_addStyle // @run-at document-end // ==/UserScript== (function () { 'use strict'; // ─────────────── 数据结构 ─────────────── let data = GM_getValue('fastfill_data_v2', { emails: ["example@gmail.com", "test@outlook.com"], phones: ["13812345678", "13900002222"], passwords: ["Abc123456!", "Passw0rd2025", "MySecret2026"] }); let panelPos = GM_getValue('fastfill_panel_pos', { bottom: 24, right: 24 }); let panelVisible = GM_getValue('fastfill_panel_visible', false); // 默认隐藏 let panel = null; // ─────────────── CSS ─────────────── GM_addStyle(` #fastfill-panel { position: fixed; z-index: 999998; width: 260px; max-height: 82vh; overflow-y: auto; background: rgba(28, 28, 36, 0.96); backdrop-filter: blur(12px); color: #e0e0ff; border-radius: 16px; box-shadow: 0 12px 44px rgba(0,0,0,0.65); font-family: system-ui, sans-serif; font-size: 14px; padding: 14px 16px; border: 1px solid rgba(100,100,160,0.35); user-select: none; transition: all 0.2s ease, opacity 0.3s, transform 0.3s; } #fastfill-panel.hidden { opacity: 0; transform: scale(0.88) translateY(20px); pointer-events: none; } #fastfill-header { font-weight: 600; color: #a5b4fc; margin-bottom: 12px; display: flex; justify-content: space-between; align-items: center; cursor: move; } .fastfill-section-title { color: #c7d2fe; font-size: 13.5px; font-weight: 600; margin: 14px 0 6px; } .fastfill-item { padding: 8px 12px; margin: 5px 0; background: rgba(45,45,65,0.7); border-radius: 8px; cursor: pointer; transition: all 0.14s; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .fastfill-item:hover { background: rgba(70,70,110,0.9); transform: translateX(3px); } .fastfill-item.email { color: #a5b4fc; } .fastfill-item.phone { color: #86efac; } .fastfill-item.password { color: #fbbf24; } #fastfill-btn-area { margin-top: 18px; display: flex; gap: 8px; flex-wrap: wrap; } .fastfill-btn { flex: 1; min-width: 78px; padding: 8px 10px; border-radius: 8px; text-align: center; cursor: pointer; font-size: 13px; background: #4b5563; color: #e0e0ff; } .fastfill-btn:hover { background: #6366f1; color: white; } .fastfill-btn.primary { background: linear-gradient(135deg, #6366f1, #8b5cf6); } `); // ─────────────── 工具函数 ─────────────── function saveData() { GM_setValue('fastfill_data_v2', data); } function fillField(value, matcher, preferEmpty = true) { document.querySelectorAll('input:not([type="hidden"]):not([type="submit"]):not([type="button"])').forEach(el => { if (!matcher(el) || !el.offsetParent) return; if (preferEmpty && el.value) return; if (!preferEmpty && el.value && !confirm(`是否覆盖?\n原: ${el.value}\n新: ${value}`)) return; el.value = value; el.dispatchEvent(new Event('input', {bubbles: true})); el.dispatchEvent(new Event('change', {bubbles: true})); }); } function fillEmail(v) { fillField(v, el => /email|mail|邮箱|account|user/i.test((el.name||'')+(el.id||'')+(el.placeholder||''))); } function fillPhone(v) { fillField(v, el => /phone|mobile|tel|手机|电话/i.test((el.name||'')+(el.id||'')+(el.placeholder||''))); } function fillPassword(v) { fillField(v, el => /pass|pwd|password|密码|确认密码|confirm/i.test((el.name||'')+(el.id||'')+(el.placeholder||'')), false); } // ─────────────── 面板创建/更新 ─────────────── function createOrUpdatePanel() { if (panel) panel.remove(); if (!panelVisible) return; panel = document.createElement('div'); panel.id = 'fastfill-panel'; panel.style.bottom = panelPos.bottom + 'px'; panel.style.right = panelPos.right + 'px'; panel.innerHTML = `
常用信息助手 ×
邮箱
手机号
常用密码
导出
导入
管理
`; document.body.appendChild(panel); // 渲染列表 const sections = [ { id: 'email-list', arr: data.emails, cls: 'email', fill: fillEmail }, { id: 'phone-list', arr: data.phones, cls: 'phone', fill: fillPhone }, { id: 'password-list', arr: data.passwords, cls: 'password', fill: fillPassword } ]; sections.forEach(sec => { const container = panel.querySelector('#' + sec.id); container.innerHTML = sec.arr.map(v => `
${v}
` ).join(''); container.querySelectorAll('.fastfill-item').forEach(item => { item.onclick = () => sec.fill(item.textContent.trim()); }); }); // 关闭 → 隐藏 panel.querySelector('#fastfill-close').onclick = hidePanel; // 拖拽(省略不变,保持原样) let drag = { active: false, sx:0, sy:0, sr:0, sb:0 }; const header = panel.querySelector('#fastfill-header'); header.onmousedown = e => { if (e.target.id === 'fastfill-close') return; drag.active = true; drag.sx = e.clientX; drag.sy = e.clientY; drag.sr = parseFloat(panel.style.right || 24); drag.sb = parseFloat(panel.style.bottom || 24); e.preventDefault(); }; document.onmousemove = e => { if (!drag.active) return; const dx = e.clientX - drag.sx; const dy = e.clientY - drag.sy; panelPos.right = Math.max(10, drag.sr - dx); panelPos.bottom = Math.max(10, drag.sb - dy); panel.style.right = panelPos.right + 'px'; panel.style.bottom = panelPos.bottom + 'px'; }; document.onmouseup = () => { if (drag.active) { drag.active = false; GM_setValue('fastfill_panel_pos', panelPos); } }; // 导出(使用 navigator.clipboard + fallback) panel.querySelector('#fastfill-export').onclick = () => { const json = JSON.stringify(data, null, 2); if (navigator.clipboard && navigator.clipboard.writeText) { navigator.clipboard.writeText(json) .then(() => { alert("已复制到剪贴板!\n可粘贴到记事本、微信、邮箱等地方保存"); }) .catch(err => { console.error('Clipboard API 失败:', err); fallbackCopy(json); }); } else { fallbackCopy(json); } function fallbackCopy(text) { prompt( "自动复制失败,请手动复制以下全部内容(全选 → Ctrl+C)\n完成后点确定:\n\n", text ); } }; // 导入(省略不变) panel.querySelector('#fastfill-import').onclick = () => { const txt = prompt("请粘贴之前导出的完整 JSON:", ""); if (!txt) return; try { const obj = JSON.parse(txt); ['emails','phones','passwords'].forEach(k => { if (Array.isArray(obj[k])) { data[k] = obj[k].filter(v => typeof v === 'string' && v.trim()); } }); saveData(); alert("导入成功"); createOrUpdatePanel(); } catch(e) { alert("JSON 格式错误,请检查是否完整复制"); } }; // 管理 panel.querySelector('#fastfill-manage').onclick = showManageModal; } function showPanel() { panelVisible = true; GM_setValue('fastfill_panel_visible', true); createOrUpdatePanel(); } function hidePanel() { panelVisible = false; GM_setValue('fastfill_panel_visible', false); if (panel) { panel.classList.add('hidden'); setTimeout(() => { panel.remove(); panel = null; }, 320); } } function togglePanel() { panelVisible ? hidePanel() : showPanel(); } // ─────────────── 快捷键:Delete 键 ─────────────── document.addEventListener('keydown', e => { if (e.key === 'Delete' || e.key === 'Del') { // 防止在输入框中误触发(可选:如果你希望在输入框里也能用,可注释掉下面这行) if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA' || e.target.isContentEditable) return; e.preventDefault(); togglePanel(); } }); // ─────────────── 管理弹窗(保持不变) ─────────────── function showManageModal() { const old = document.getElementById('fastfill-modal'); if (old) old.remove(); const modal = document.createElement('div'); modal.id = 'fastfill-modal'; modal.innerHTML = `

管理常用信息

邮箱
手机号
密码
`; document.body.appendChild(modal); function renderTab(type) { const cont = document.getElementById(type + '-edit'); const arr = data[type + 's'] || []; cont.innerHTML = arr.map((v,i) => `
`).join(''); } ['email','phone','password'].forEach(t => renderTab(t)); // tab 切换 modal.querySelectorAll('.tab').forEach(tab => { tab.onclick = () => { modal.querySelectorAll('.tab').forEach(t => { t.classList.remove('active'); t.style.borderBottomColor = 'transparent'; }); modal.querySelectorAll('[id^="tab-"]').forEach(c => c.style.display = 'none'); tab.classList.add('active'); tab.style.borderBottomColor = '#6366f1'; document.getElementById('tab-' + tab.dataset.tab).style.display = 'block'; }; }); // 添加、保存、删除逻辑(保持不变) modal.querySelectorAll('.add-btn').forEach(btn => { btn.onclick = () => { const input = btn.previousElementSibling; const val = input.value.trim(); if (!val) return; const type = btn.closest('[id^="tab-"]').id.replace('tab-', ''); const arr = data[type + 's']; if (arr.includes(val)) return alert('已存在'); arr.push(val); saveData(); input.value = ''; renderTab(type); }; }); modal.addEventListener('click', e => { if (!e.target.classList.contains('save-btn') && !e.target.classList.contains('del-btn')) return; const row = e.target.closest('div'); const inp = row.querySelector('input'); const idx = +inp.dataset.i; const typ = inp.dataset.t; const arr = data[typ + 's']; if (e.target.classList.contains('save-btn')) { const nv = inp.value.trim(); if (nv && nv !== arr[idx]) { arr[idx] = nv; saveData(); renderTab(typ); } } else if (e.target.classList.contains('del-btn')) { if (!confirm('确认删除?')) return; arr.splice(idx, 1); saveData(); renderTab(typ); } }); modal.querySelector('#modal-close').onclick = () => { modal.remove(); }; } // ─────────────── 自动检测表单 ─────────────── function hasTargetInput() { return !!document.querySelector(` input[type="email" i], input[type="tel" i], input[type="password" i], input[name*="email" i], input[name*="phone" i], input[name*="pass" i], input[placeholder*="邮箱" i], input[placeholder*="手机" i], input[placeholder*="密码" i] `); } function autoCheck() { if (panelVisible && hasTargetInput() && !panel) { createOrUpdatePanel(); } else if (panel && !hasTargetInput()) { hidePanel(); } } setTimeout(autoCheck, 1200); const observer = new MutationObserver(autoCheck); observer.observe(document.body, { childList: true, subtree: true }); // 菜单辅助 GM_registerMenuCommand("显示/隐藏面板 (Delete 键)", togglePanel); GM_registerMenuCommand("强制刷新面板", createOrUpdatePanel); // 首次提示(更新快捷键说明) if (!GM_getValue('fastfill_seen_tip', false)) { setTimeout(() => { alert("快捷键:Delete 键(del键) → 显示/隐藏面板\n\n在输入框内按 Del 不会触发(避免误操作)"); GM_setValue('fastfill_seen_tip', true); }, 2000); } })();